` shows increasing values of `i`.
-
## Summary
-- Methods `setInterval(func, delay, ...args)` and `setTimeout(func, delay, ...args)` allow to run the `func` regularly/once after `delay` milliseconds.
-- To cancel the execution, we should call `clearInterval/clearTimeout` with the value returned by `setInterval/setTimeout`.
-- Nested `setTimeout` calls is a more flexible alternative to `setInterval`. Also they can guarantee the minimal time *between* the executions.
-- Zero-timeout scheduling `setTimeout(...,0)` is used to schedule the call "as soon as possible, but after the current code is complete".
-
-Some use cases of `setTimeout(...,0)`:
-- To split CPU-hungry tasks into pieces, so that the script doesn't "hang"
-- To let the browser do something else while the process is going on (paint the progress bar).
+- Methods `setTimeout(func, delay, ...args)` and `setInterval(func, delay, ...args)` allow us to run the `func` once/regularly after `delay` milliseconds.
+- To cancel the execution, we should call `clearTimeout/clearInterval` with the value returned by `setTimeout/setInterval`.
+- Nested `setTimeout` calls are a more flexible alternative to `setInterval`, allowing us to set the time *between* executions more precisely.
+- Zero delay scheduling with `setTimeout(func, 0)` (the same as `setTimeout(func)`) is used to schedule the call "as soon as possible, but after the current script is complete".
+- The browser limits the minimal delay for five or more nested calls of `setTimeout` or for `setInterval` (after 5th call) to 4ms. That's for historical reasons.
-Please note that all scheduling methods do not *guarantee* the exact delay. We should not rely on that in the scheduled code.
+Please note that all scheduling methods do not *guarantee* the exact delay.
For example, the in-browser timer may slow down for a lot of reasons:
- The CPU is overloaded.
- The browser tab is in the background mode.
-- The laptop is on battery.
+- The laptop is on battery saving mode.
-All that may increase the minimal timer resolution (the minimal delay) to 300ms or even 1000ms depending on the browser and settings.
+All that may increase the minimal timer resolution (the minimal delay) to 300ms or even 1000ms depending on the browser and OS-level performance settings.
diff --git a/1-js/06-advanced-functions/08-settimeout-setinterval/setinterval-interval.png b/1-js/06-advanced-functions/08-settimeout-setinterval/setinterval-interval.png
deleted file mode 100644
index ccafd7f144..0000000000
Binary files a/1-js/06-advanced-functions/08-settimeout-setinterval/setinterval-interval.png and /dev/null differ
diff --git a/1-js/06-advanced-functions/08-settimeout-setinterval/setinterval-interval.svg b/1-js/06-advanced-functions/08-settimeout-setinterval/setinterval-interval.svg
new file mode 100644
index 0000000000..bce7d6a843
--- /dev/null
+++ b/1-js/06-advanced-functions/08-settimeout-setinterval/setinterval-interval.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/06-advanced-functions/08-settimeout-setinterval/setinterval-interval@2x.png b/1-js/06-advanced-functions/08-settimeout-setinterval/setinterval-interval@2x.png
deleted file mode 100644
index 9fcd057eb4..0000000000
Binary files a/1-js/06-advanced-functions/08-settimeout-setinterval/setinterval-interval@2x.png and /dev/null differ
diff --git a/1-js/06-advanced-functions/08-settimeout-setinterval/settimeout-interval.png b/1-js/06-advanced-functions/08-settimeout-setinterval/settimeout-interval.png
deleted file mode 100644
index 094cf9153a..0000000000
Binary files a/1-js/06-advanced-functions/08-settimeout-setinterval/settimeout-interval.png and /dev/null differ
diff --git a/1-js/06-advanced-functions/08-settimeout-setinterval/settimeout-interval.svg b/1-js/06-advanced-functions/08-settimeout-setinterval/settimeout-interval.svg
new file mode 100644
index 0000000000..d6d233b2ba
--- /dev/null
+++ b/1-js/06-advanced-functions/08-settimeout-setinterval/settimeout-interval.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/06-advanced-functions/08-settimeout-setinterval/settimeout-interval@2x.png b/1-js/06-advanced-functions/08-settimeout-setinterval/settimeout-interval@2x.png
deleted file mode 100644
index bee585758c..0000000000
Binary files a/1-js/06-advanced-functions/08-settimeout-setinterval/settimeout-interval@2x.png and /dev/null differ
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/_js.view/solution.js b/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/_js.view/solution.js
index 9ef503703b..d5a09efb36 100644
--- a/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/_js.view/solution.js
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/_js.view/solution.js
@@ -1,11 +1,12 @@
function spy(func) {
function wrapper(...args) {
+ // using ...args instead of arguments to store "real" array in wrapper.calls
wrapper.calls.push(args);
- return func.apply(this, arguments);
+ return func.apply(this, args);
}
wrapper.calls = [];
return wrapper;
-}
\ No newline at end of file
+}
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/solution.md b/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/solution.md
index 19a072014b..0c8a211b49 100644
--- a/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/solution.md
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/solution.md
@@ -1 +1 @@
-Here we can use `calls.push(args)` to store all arguments in the log and `f.apply(this, args)` to forward the call.
+The wrapper returned by `spy(f)` should store all arguments and then use `f.apply` to forward the call.
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/solution.js b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/solution.js
index 065a77d1f9..661dd0cf41 100644
--- a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/solution.js
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/solution.js
@@ -1,15 +1,7 @@
-function debounce(f, ms) {
-
- let isCooldown = false;
-
+function debounce(func, ms) {
+ let timeout;
return function() {
- if (isCooldown) return;
-
- f.apply(this, arguments);
-
- isCooldown = true;
-
- setTimeout(() => isCooldown = false, ms);
+ clearTimeout(timeout);
+ timeout = setTimeout(() => func.apply(this, arguments), ms);
};
-
-}
\ No newline at end of file
+}
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/test.js b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/test.js
index 16dc171e1a..750e649f83 100644
--- a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/test.js
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/test.js
@@ -1,41 +1,48 @@
-describe("debounce", function() {
- before(function() {
+describe('debounce', function () {
+ before(function () {
this.clock = sinon.useFakeTimers();
});
- after(function() {
+ after(function () {
this.clock.restore();
});
- it("calls the function at maximum once in ms milliseconds", function() {
- let log = '';
+ it('for one call - runs it after given ms', function () {
+ const f = sinon.spy();
+ const debounced = debounce(f, 1000);
- function f(a) {
- log += a;
- }
+ debounced('test');
+ assert(f.notCalled, 'not called immediately');
+ this.clock.tick(1000);
+ assert(f.calledOnceWith('test'), 'called after 1000ms');
+ });
- f = debounce(f, 1000);
+ it('for 3 calls - runs the last one after given ms', function () {
+ const f = sinon.spy();
+ const debounced = debounce(f, 1000);
- f(1); // runs at once
- f(2); // ignored
+ debounced('a');
+ setTimeout(() => debounced('b'), 200); // ignored (too early)
+ setTimeout(() => debounced('c'), 500); // runs (1000 ms passed)
+ this.clock.tick(1000);
- setTimeout(() => f(3), 100); // ignored (too early)
- setTimeout(() => f(4), 1100); // runs (1000 ms passed)
- setTimeout(() => f(5), 1500); // ignored (less than 1000 ms from the last run)
+ assert(f.notCalled, 'not called after 1000ms');
- this.clock.tick(5000);
- assert.equal(log, "14");
+ this.clock.tick(500);
+
+ assert(f.calledOnceWith('c'), 'called after 1500ms');
});
- it("keeps the context of the call", function() {
+ it('keeps the context of the call', function () {
let obj = {
f() {
assert.equal(this, obj);
- }
+ },
};
obj.f = debounce(obj.f, 1000);
- obj.f("test");
+ obj.f('test');
+ this.clock.tick(5000);
});
-
-});
\ No newline at end of file
+
+});
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/debounce.svg b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/debounce.svg
new file mode 100644
index 0000000000..e624ce0203
--- /dev/null
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/debounce.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/debounce.view/index.html b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/debounce.view/index.html
new file mode 100644
index 0000000000..e3b4d5842f
--- /dev/null
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/debounce.view/index.html
@@ -0,0 +1,24 @@
+
+
+
+Function handler is called on this input:
+
+
+
+
+
+Debounced function debounce(handler, 1000) is called on this input:
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/solution.md b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/solution.md
index 4f5867ded9..83e75f3158 100644
--- a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/solution.md
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/solution.md
@@ -1,28 +1,13 @@
```js demo
-function debounce(f, ms) {
-
- let isCooldown = false;
-
+function debounce(func, ms) {
+ let timeout;
return function() {
- if (isCooldown) return;
-
- f.apply(this, arguments);
-
- isCooldown = true;
-
- setTimeout(() => isCooldown = false, ms);
+ clearTimeout(timeout);
+ timeout = setTimeout(() => func.apply(this, arguments), ms);
};
-
}
-```
-
-A call to `debounce` returns a wrapper. There may be two states:
-- `isCooldown = false` -- ready to run.
-- `isCooldown = true` -- waiting for the timeout.
-
-In the first call `isCooldown` is falsy, so the call proceeds, and the state changes to `true`.
+```
-While `isCooldown` is true, all other calls are ignored.
+A call to `debounce` returns a wrapper. When called, it schedules the original function call after given `ms` and cancels the previous such timeout.
-Then `setTimeout` reverts it to `false` after the given delay.
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/task.md b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/task.md
index 466c6bc3f7..5b0fcc5f87 100644
--- a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/task.md
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/task.md
@@ -4,21 +4,48 @@ importance: 5
# Debounce decorator
-The result of `debounce(f, ms)` decorator should be a wrapper that passes the call to `f` at maximum once per `ms` milliseconds.
+The result of `debounce(f, ms)` decorator is a wrapper that suspends calls to `f` until there's `ms` milliseconds of inactivity (no calls, "cooldown period"), then invokes `f` once with the latest arguments.
-In other words, when we call a "debounced" function, it guarantees that all other future in the closest `ms` milliseconds will be ignored.
+In other words, `debounce` is like a secretary that accepts "phone calls", and waits until there's `ms` milliseconds of being quiet. And only then it transfers the latest call information to "the boss" (calls the actual `f`).
-For instance:
+For instance, we had a function `f` and replaced it with `f = debounce(f, 1000)`.
-```js no-beautify
-let f = debounce(alert, 1000);
+Then if the wrapped function is called at 0ms, 200ms and 500ms, and then there are no calls, then the actual `f` will be only called once, at 1500ms. That is: after the cooldown period of 1000ms from the last call.
-f(1); // runs immediately
-f(2); // ignored
+
-setTimeout( () => f(3), 100); // ignored ( only 100 ms passed )
-setTimeout( () => f(4), 1100); // runs
-setTimeout( () => f(5), 1500); // ignored (less than 1000 ms from the last run)
+...And it will get the arguments of the very last call, other calls are ignored.
+
+Here's the code for it (uses the debounce decorator from the [Lodash library](https://lodash.com/docs/4.17.15#debounce)):
+
+```js
+let f = _.debounce(alert, 1000);
+
+f("a");
+setTimeout( () => f("b"), 200);
+setTimeout( () => f("c"), 500);
+// debounced function waits 1000ms after the last call and then runs: alert("c")
+```
+
+Now a practical example. Let's say, the user types something, and we'd like to send a request to the server when the input is finished.
+
+There's no point in sending the request for every character typed. Instead we'd like to wait, and then process the whole result.
+
+In a web-browser, we can setup an event handler -- a function that's called on every change of an input field. Normally, an event handler is called very often, for every typed key. But if we `debounce` it by 1000ms, then it will be only called once, after 1000ms after the last input.
+
+```online
+
+In this live example, the handler puts the result into a box below, try it:
+
+[iframe border=1 src="https://github.com/debounce" height=200]
+
+See? The second input calls the debounced function, so its content is processed after 1000ms from the last input.
```
-In practice `debounce` is useful for functions that retrieve/update something when we know that nothing new can be done in such a short period of time, so it's better not to waste resources.
\ No newline at end of file
+So, `debounce` is a great way to process a sequence of events: be it a sequence of key presses, mouse movements or something else.
+
+It waits the given time after the last call, and then runs its function, that can process the result.
+
+The task is to implement `debounce` decorator.
+
+Hint: that's just a few lines if you think about it :)
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/_js.view/test.js b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/_js.view/test.js
index 5339c8d117..e671438f6f 100644
--- a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/_js.view/test.js
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/_js.view/test.js
@@ -7,8 +7,8 @@ describe("throttle(f, 1000)", function() {
}
before(function() {
- f1000 = throttle(f, 1000);
this.clock = sinon.useFakeTimers();
+ f1000 = throttle(f, 1000);
});
it("the first call runs now", function() {
@@ -44,4 +44,20 @@ describe("throttle(f, 1000)", function() {
this.clock.restore();
});
-});
\ No newline at end of file
+});
+
+describe('throttle', () => {
+
+ it('runs a forwarded call once', done => {
+ let log = '';
+ const f = str => log += str;
+ const f10 = throttle(f, 10);
+ f10('once');
+
+ setTimeout(() => {
+ assert.equal(log, 'once');
+ done();
+ }, 20);
+ });
+
+});
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/solution.md b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/solution.md
index c844016d3b..6950664be1 100644
--- a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/solution.md
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/solution.md
@@ -12,11 +12,10 @@ function throttle(func, ms) {
savedThis = this;
return;
}
+ isThrottled = true;
func.apply(this, arguments); // (1)
- isThrottled = true;
-
setTimeout(function() {
isThrottled = false; // (3)
if (savedArgs) {
@@ -33,7 +32,7 @@ function throttle(func, ms) {
A call to `throttle(func, ms)` returns `wrapper`.
1. During the first call, the `wrapper` just runs `func` and sets the cooldown state (`isThrottled = true`).
-2. In this state all calls memorized in `savedArgs/savedThis`. Please note that both the context and the arguments are equally important and should be memorized. We need them simultaneously to reproduce the call.
-3. ...Then after `ms` milliseconds pass, `setTimeout` triggers. The cooldown state is removed (`isThrottled = false`). And if we had ignored calls, then `wrapper` is executed with last memorized arguments and context.
+2. In this state all calls are memorized in `savedArgs/savedThis`. Please note that both the context and the arguments are equally important and should be memorized. We need them simultaneously to reproduce the call.
+3. After `ms` milliseconds pass, `setTimeout` triggers. The cooldown state is removed (`isThrottled = false`) and, if we had ignored calls, `wrapper` is executed with the last memorized arguments and context.
The 3rd step runs not `func`, but `wrapper`, because we not only need to execute `func`, but once again enter the cooldown state and setup the timeout to reset it.
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md
index 716b4e1d6b..cbd4731960 100644
--- a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md
@@ -4,35 +4,40 @@ importance: 5
# Throttle decorator
-Create a "throttling" decorator `throttle(f, ms)` -- that returns a wrapper, passing the call to `f` at maximum once per `ms` milliseconds. Those calls that fall into the "cooldown" period, are ignored.
+Create a "throttling" decorator `throttle(f, ms)` -- that returns a wrapper.
-**The difference with `debounce` -- if an ignored call is the last during the cooldown, then it executes at the end of the delay.**
+When it's called multiple times, it passes the call to `f` at maximum once per `ms` milliseconds.
+
+Compared to the debounce decorator, the behavior is completely different:
+- `debounce` runs the function once after the "cooldown" period. Good for processing the final result.
+- `throttle` runs it not more often than given `ms` time. Good for regular updates that shouldn't be very often.
+
+In other words, `throttle` is like a secretary that accepts phone calls, but bothers the boss (calls the actual `f`) not more often than once per `ms` milliseconds.
Let's check the real-life application to better understand that requirement and to see where it comes from.
**For instance, we want to track mouse movements.**
-In browser we can setup a function to run at every mouse micro-movement and get the pointer location as it moves. During an active mouse usage, this function usually runs very frequently, can be something like 100 times per second (every 10 ms).
-
-**The tracking function should update some information on the web-page.**
+In a browser we can setup a function to run at every mouse movement and get the pointer location as it moves. During an active mouse usage, this function usually runs very frequently, can be something like 100 times per second (every 10 ms).
+**We'd like to update some information on the web-page when the pointer moves.**
-Updating function `update()` is too heavy to do it on every micro-movement. There is also no sense in making it more often than once per 100ms.
+...But updating function `update()` is too heavy to do it on every micro-movement. There is also no sense in updating more often than once per 100ms.
-So we'll assign `throttle(update, 100)` as the function to run on each mouse move instead of the original `update()`. The decorator will be called often, but `update()` will be called at maximum once per 100ms.
+So we'll wrap it into the decorator: use `throttle(update, 100)` as the function to run on each mouse move instead of the original `update()`. The decorator will be called often, but forward the call to `update()` at maximum once per 100ms.
Visually, it will look like this:
-1. For the first mouse movement the decorated variant passes the call to `update`. That's important, the user sees our reaction to their move immediately.
+1. For the first mouse movement the decorated variant immediately passes the call to `update`. That's important, the user sees our reaction to their move immediately.
2. Then as the mouse moves on, until `100ms` nothing happens. The decorated variant ignores calls.
-3. At the end of `100ms` -- one more `update` happens with the last coordinates.
-4. Then, finally, the mouse stops somewhere. The decorated variant waits until `100ms` expire and then runs `update` with last coordinates. So, perhaps the most important, the final mouse coordinates are processed.
+3. At the end of `100ms` -- one more `update` happens with the last coordinates.
+4. Then, finally, the mouse stops somewhere. The decorated variant waits until `100ms` expire and then runs `update` with last coordinates. So, quite important, the final mouse coordinates are processed.
A code example:
```js
function f(a) {
- console.log(a)
-};
+ console.log(a);
+}
// f1000 passes calls to f at maximum once per 1000 ms
let f1000 = throttle(f, 1000);
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/article.md b/1-js/06-advanced-functions/09-call-apply-decorators/article.md
index 75c510d1e4..c5d785493c 100644
--- a/1-js/06-advanced-functions/09-call-apply-decorators/article.md
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/article.md
@@ -6,9 +6,9 @@ JavaScript gives exceptional flexibility when dealing with functions. They can b
Let's say we have a function `slow(x)` which is CPU-heavy, but its results are stable. In other words, for the same `x` it always returns the same result.
-If the function is called often, we may want to cache (remember) the results for different `x` to avoid spending extra-time on recalculations.
+If the function is called often, we may want to cache (remember) the results to avoid spending extra-time on recalculations.
-But instead of adding that functionality into `slow()` we'll create a wrapper. As we'll see, there are many benefits of doing so.
+But instead of adding that functionality into `slow()` we'll create a wrapper function, that adds caching. As we'll see, there are many benefits of doing so.
Here's the code, and explanations follow:
@@ -23,24 +23,24 @@ function cachingDecorator(func) {
let cache = new Map();
return function(x) {
- if (cache.has(x)) { // if the result is in the map
- return cache.get(x); // return it
+ if (cache.has(x)) { // if there's such key in cache
+ return cache.get(x); // read the result from it
}
- let result = func(x); // otherwise call func
+ let result = func(x); // otherwise call func
- cache.set(x, result); // and cache (remember) the result
+ cache.set(x, result); // and cache (remember) the result
return result;
};
}
slow = cachingDecorator(slow);
-alert( slow(1) ); // slow(1) is cached
-alert( "Again: " + slow(1) ); // the same
+alert( slow(1) ); // slow(1) is cached and the result returned
+alert( "Again: " + slow(1) ); // slow(1) result returned from cache
-alert( slow(2) ); // slow(2) is cached
-alert( "Again: " + slow(2) ); // the same as the previous line
+alert( slow(2) ); // slow(2) is cached and the result returned
+alert( "Again: " + slow(2) ); // slow(2) result returned from cache
```
In the code above `cachingDecorator` is a *decorator*: a special function that takes another function and alters its behavior.
@@ -49,21 +49,18 @@ The idea is that we can call `cachingDecorator` for any function, and it will re
By separating caching from the main function code we also keep the main code simpler.
-Now let's get into details of how it works.
-
The result of `cachingDecorator(func)` is a "wrapper": `function(x)` that "wraps" the call of `func(x)` into caching logic:
-
+
-As we can see, the wrapper returns the result of `func(x)` "as is". From an outside code, the wrapped `slow` function still does the same. It just got a caching aspect added to its behavior.
+From an outside code, the wrapped `slow` function still does the same. It just got a caching aspect added to its behavior.
To summarize, there are several benefits of using a separate `cachingDecorator` instead of altering the code of `slow` itself:
- The `cachingDecorator` is reusable. We can apply it to another function.
-- The caching logic is separate, it did not increase the complexity of `slow` itself (if there were any).
+- The caching logic is separate, it did not increase the complexity of `slow` itself (if there was any).
- We can combine multiple decorators if needed (other decorators will follow).
-
## Using "func.call" for the context
The caching decorator mentioned above is not suited to work with object methods.
@@ -78,7 +75,7 @@ let worker = {
},
slow(x) {
- // actually, there can be a scary CPU-heavy task here
+ // scary CPU-heavy task here
alert("Called with " + x);
return x * this.someMethod(); // (*)
}
@@ -152,8 +149,8 @@ let user = { name: "John" };
let admin = { name: "Admin" };
// use call to pass different objects as "this"
-sayHi.call( user ); // this = John
-sayHi.call( admin ); // this = Admin
+sayHi.call( user ); // John
+sayHi.call( admin ); // Admin
```
And here we use `call` to call `say` with the given context and phrase:
@@ -170,10 +167,8 @@ let user = { name: "John" };
say.call( user, "Hello" ); // John: Hello
```
-
In our case, we can use `call` in the wrapper to pass the context to the original function:
-
```js run
let worker = {
someMethod() {
@@ -214,7 +209,7 @@ To make it all clear, let's see more deeply how `this` is passed along:
2. So when `worker.slow(2)` is executed, the wrapper gets `2` as an argument and `this=worker` (it's the object before dot).
3. Inside the wrapper, assuming the result is not yet cached, `func.call(this, x)` passes the current `this` (`=worker`) and the current argument (`=2`) to the original method.
-## Going multi-argument with "func.apply"
+## Going multi-argument
Now let's make `cachingDecorator` even more universal. Till now it was working only with single-argument functions.
@@ -231,9 +226,7 @@ let worker = {
worker.slow = cachingDecorator(worker.slow);
```
-We have two tasks to solve here.
-
-First is how to use both arguments `min` and `max` for the key in `cache` map. Previously, for a single argument `x` we could just `cache.set(x, result)` to save the result and `cache.get(x)` to retrieve it. But now we need to remember the result for a *combination of arguments* `(min,max)`. The native `Map` takes single value only as the key.
+Previously, for a single argument `x` we could just `cache.set(x, result)` to save the result and `cache.get(x)` to retrieve it. But now we need to remember the result for a *combination of arguments* `(min,max)`. The native `Map` takes single value only as the key.
There are many solutions possible:
@@ -241,85 +234,11 @@ There are many solutions possible:
2. Use nested maps: `cache.set(min)` will be a `Map` that stores the pair `(max, result)`. So we can get `result` as `cache.get(min).get(max)`.
3. Join two values into one. In our particular case we can just use a string `"min,max"` as the `Map` key. For flexibility, we can allow to provide a *hashing function* for the decorator, that knows how to make one value from many.
-
For many practical applications, the 3rd variant is good enough, so we'll stick to it.
-The second task to solve is how to pass many arguments to `func`. Currently, the wrapper `function(x)` assumes a single argument, and `func.call(this, x)` passes it.
-
-Here we can use another built-in method [func.apply](mdn:js/Function/apply).
-
-The syntax is:
-
-```js
-func.apply(context, args)
-```
-
-It runs the `func` setting `this=context` and using an array-like object `args` as the list of arguments.
-
-
-For instance, these two calls are almost the same:
-
-```js
-func(1, 2, 3);
-func.apply(context, [1, 2, 3])
-```
-
-Both run `func` giving it arguments `1,2,3`. But `apply` also sets `this=context`.
-
-For instance, here `say` is called with `this=user` and `messageData` as a list of arguments:
-
-```js run
-function say(time, phrase) {
- alert(`[${time}] ${this.name}: ${phrase}`);
-}
-
-let user = { name: "John" };
-
-let messageData = ['10:00', 'Hello']; // become time and phrase
-
-*!*
-// user becomes this, messageData is passed as a list of arguments (time, phrase)
-say.apply(user, messageData); // [10:00] John: Hello (this=user)
-*/!*
-```
-
-The only syntax difference between `call` and `apply` is that `call` expects a list of arguments, while `apply` takes an array-like object with them.
-
-We already know the spread operator `...` from the chapter that can pass an array (or any iterable) as a list of arguments. So if we use it with `call`, we can achieve almost the same as `apply`.
-
-These two calls are almost equivalent:
-
-```js
-let args = [1, 2, 3];
-
-*!*
-func.call(context, ...args); // pass an array as list with spread operator
-func.apply(context, args); // is same as using apply
-*/!*
-```
-
-If we look more closely, there's a minor difference between such uses of `call` and `apply`.
-
-- The spread operator `...` allows to pass *iterable* `args` as the list to `call`.
-- The `apply` accepts only *array-like* `args`.
-
-So, these calls complement each other. Where we expect an iterable, `call` works, where we expect an array-like, `apply` works.
-
-And if `args` is both iterable and array-like, like a real array, then we technically could use any of them, but `apply` will probably be faster, because it's a single operation. Most JavaScript engines internally optimize it better than a pair `call + spread`.
-
-One of the most important uses of `apply` is passing the call to another function, like this:
-
-```js
-let wrapper = function() {
- return anotherFunction.apply(this, arguments);
-};
-```
-
-That's called *call forwarding*. The `wrapper` passes everything it gets: the context `this` and arguments to `anotherFunction` and returns back its result.
+Also we need to pass not just `x`, but all arguments in `func.call`. Let's recall that in a `function()` we can get a pseudo-array of its arguments as `arguments`, so `func.call(this, x)` should be replaced with `func.call(this, ...arguments)`.
-When an external code calls such `wrapper`, it is indistinguishable from the call of the original function.
-
-Now let's bake it all into the more powerful `cachingDecorator`:
+Here's a more powerful `cachingDecorator`:
```js run
let worker = {
@@ -340,7 +259,7 @@ function cachingDecorator(func, hash) {
}
*!*
- let result = func.apply(this, arguments); // (**)
+ let result = func.call(this, ...arguments); // (**)
*/!*
cache.set(key, result);
@@ -358,13 +277,54 @@ alert( worker.slow(3, 5) ); // works
alert( "Again " + worker.slow(3, 5) ); // same (cached)
```
-Now the wrapper operates with any number of arguments.
+Now it works with any number of arguments (though the hash function would also need to be adjusted to allow any number of arguments. An interesting way to handle this will be covered below).
There are two changes:
- In the line `(*)` it calls `hash` to create a single key from `arguments`. Here we use a simple "joining" function that turns arguments `(3, 5)` into the key `"3,5"`. More complex cases may require other hashing functions.
-- Then `(**)` uses `func.apply` to pass both the context and all arguments the wrapper got (no matter how many) to the original function.
+- Then `(**)` uses `func.call(this, ...arguments)` to pass both the context and all arguments the wrapper got (not just the first one) to the original function.
+
+## func.apply
+
+Instead of `func.call(this, ...arguments)` we could use `func.apply(this, arguments)`.
+
+The syntax of built-in method [func.apply](mdn:js/Function/apply) is:
+
+```js
+func.apply(context, args)
+```
+
+It runs the `func` setting `this=context` and using an array-like object `args` as the list of arguments.
+
+The only syntax difference between `call` and `apply` is that `call` expects a list of arguments, while `apply` takes an array-like object with them.
+
+So these two calls are almost equivalent:
+
+```js
+func.call(context, ...args);
+func.apply(context, args);
+```
+
+They perform the same call of `func` with given context and arguments.
+
+There's only a subtle difference regarding `args`:
+
+- The spread syntax `...` allows to pass *iterable* `args` as the list to `call`.
+- The `apply` accepts only *array-like* `args`.
+...And for objects that are both iterable and array-like, such as a real array, we can use any of them, but `apply` will probably be faster, because most JavaScript engines internally optimize it better.
+
+Passing all arguments along with the context to another function is called *call forwarding*.
+
+That's the simplest form of it:
+
+```js
+let wrapper = function() {
+ return func.apply(this, arguments);
+};
+```
+
+When an external code calls such `wrapper`, it is indistinguishable from the call of the original function `func`.
## Borrowing a method [#method-borrowing]
@@ -386,7 +346,7 @@ function hash(args) {
}
```
-...Unfortunately, that won't work. Because we are calling `hash(arguments)` and `arguments` object is both iterable and array-like, but not a real array.
+...Unfortunately, that won't work. Because we are calling `hash(arguments)`, and `arguments` object is both iterable and array-like, but not a real array.
So calling `join` on it would fail, as we can see below:
@@ -414,7 +374,7 @@ hash(1, 2);
The trick is called *method borrowing*.
-We take (borrow) a join method from a regular array `[].join`. And use `[].join.call` to run it in the context of `arguments`.
+We take (borrow) a join method from a regular array (`[].join`) and use `[].join.call` to run it in the context of `arguments`.
Why does it work?
@@ -432,12 +392,20 @@ Taken from the specification almost "as-is":
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`.
+## Decorators and function properties
+
+It is generally safe to replace a function or a method with a decorated one, except for one little thing. If the original function had properties on it, like `func.calledCount` or whatever, then the decorated one will not provide them. Because that is a wrapper. So one needs to be careful if one uses them.
+
+E.g. in the example above if `slow` function had any properties on it, then `cachingDecorator(slow)` is a wrapper without them.
+
+Some decorators may provide their own properties. E.g. a decorator may count how many times a function was invoked and how much time it took, and expose this information via wrapper properties.
+
+There exists a way to create decorators that keep access to function properties, but this requires using a special `Proxy` object to wrap a function. We'll discuss it later in the article .
+
## Summary
*Decorator* is a wrapper around a function that alters its behavior. The main job is still carried out by the function.
-It is generally safe to replace a function or a method with a decorated one, except for one little thing. If the original function had properties on it, like `func.calledCount` or whatever, then the decorated one will not provide them. Because that is a wrapper. So one needs to be careful if one uses them. Some decorators provide their own properties.
-
Decorators can be seen as "features" or "aspects" that can be added to a function. We can add one or add many. And all this without changing its code!
To implement `cachingDecorator`, we studied methods:
@@ -450,10 +418,9 @@ The generic *call forwarding* is usually done with `apply`:
```js
let wrapper = function() {
return original.apply(this, arguments);
-}
+};
```
-We also saw an example of *method borrowing* when we take a method from an object and `call` it in the context of another object. It is quite common to take array methods and apply them to arguments. The alternative is to use rest parameters object that is a real array.
-
+We also saw an example of *method borrowing* when we take a method from an object and `call` it in the context of another object. It is quite common to take array methods and apply them to `arguments`. The alternative is to use rest parameters object that is a real array.
There are many decorators there in the wild. Check how well you got them by solving the tasks of this chapter.
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/decorator-makecaching-wrapper.png b/1-js/06-advanced-functions/09-call-apply-decorators/decorator-makecaching-wrapper.png
deleted file mode 100644
index e45e486782..0000000000
Binary files a/1-js/06-advanced-functions/09-call-apply-decorators/decorator-makecaching-wrapper.png and /dev/null differ
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/decorator-makecaching-wrapper.svg b/1-js/06-advanced-functions/09-call-apply-decorators/decorator-makecaching-wrapper.svg
new file mode 100644
index 0000000000..9b63cb982b
--- /dev/null
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/decorator-makecaching-wrapper.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/decorator-makecaching-wrapper@2x.png b/1-js/06-advanced-functions/09-call-apply-decorators/decorator-makecaching-wrapper@2x.png
deleted file mode 100644
index eec94c5bca..0000000000
Binary files a/1-js/06-advanced-functions/09-call-apply-decorators/decorator-makecaching-wrapper@2x.png and /dev/null differ
diff --git a/1-js/06-advanced-functions/10-bind/4-function-property-after-bind/task.md b/1-js/06-advanced-functions/10-bind/4-function-property-after-bind/task.md
index 8cd18ec56c..d6cfb44bf8 100644
--- a/1-js/06-advanced-functions/10-bind/4-function-property-after-bind/task.md
+++ b/1-js/06-advanced-functions/10-bind/4-function-property-after-bind/task.md
@@ -4,7 +4,7 @@ importance: 5
# Function property after bind
-There's a value in the property of a function. Will it change after `bind`? Why, elaborate?
+There's a value in the property of a function. Will it change after `bind`? Why, or why not?
```js run
function sayHi() {
diff --git a/1-js/06-advanced-functions/10-bind/5-question-use-bind/solution.md b/1-js/06-advanced-functions/10-bind/5-question-use-bind/solution.md
index 0cb673b12b..4a381c0b40 100644
--- a/1-js/06-advanced-functions/10-bind/5-question-use-bind/solution.md
+++ b/1-js/06-advanced-functions/10-bind/5-question-use-bind/solution.md
@@ -1,5 +1,5 @@
-The error occurs because `ask` gets functions `loginOk/loginFail` without the object.
+The error occurs because `askPassword` gets functions `loginOk/loginFail` without the object.
When it calls them, they naturally assume `this=undefined`.
@@ -38,6 +38,6 @@ An alternative solution could be:
askPassword(() => user.loginOk(), () => user.loginFail());
```
-Usually that also works, but may fail in more complex situations where `user` has a chance of being overwritten between the moments of asking and running `() => user.loginOk()`.
-
+Usually that also works and looks good.
+It's a bit less reliable though in more complex situations where `user` variable might change *after* `askPassword` is called, but *before* the visitor answers and calls `() => user.loginOk()`.
diff --git a/1-js/06-advanced-functions/10-bind/5-question-use-bind/task.md b/1-js/06-advanced-functions/10-bind/5-question-use-bind/task.md
index eb19e6644d..fe6a9b4eb9 100644
--- a/1-js/06-advanced-functions/10-bind/5-question-use-bind/task.md
+++ b/1-js/06-advanced-functions/10-bind/5-question-use-bind/task.md
@@ -2,7 +2,7 @@ importance: 5
---
-# Ask losing this
+# Fix a function that loses "this"
The call to `askPassword()` in the code below should check the password and then call `user.loginOk/loginFail` depending on the answer.
@@ -34,5 +34,3 @@ let user = {
askPassword(user.loginOk, user.loginFail);
*/!*
```
-
-
diff --git a/1-js/06-advanced-functions/11-currying-partials/1-ask-currying/solution.md b/1-js/06-advanced-functions/10-bind/6-ask-partial/solution.md
similarity index 100%
rename from 1-js/06-advanced-functions/11-currying-partials/1-ask-currying/solution.md
rename to 1-js/06-advanced-functions/10-bind/6-ask-partial/solution.md
diff --git a/1-js/06-advanced-functions/10-bind/6-ask-partial/task.md b/1-js/06-advanced-functions/10-bind/6-ask-partial/task.md
new file mode 100644
index 0000000000..c90851c2bd
--- /dev/null
+++ b/1-js/06-advanced-functions/10-bind/6-ask-partial/task.md
@@ -0,0 +1,34 @@
+importance: 5
+
+---
+
+# Partial application for login
+
+The task is a little more complex variant of .
+
+The `user` object was modified. Now instead of two functions `loginOk/loginFail`, it has a single function `user.login(true/false)`.
+
+What should we pass `askPassword` in the code below, so that it calls `user.login(true)` as `ok` and `user.login(false)` as `fail`?
+
+```js
+function askPassword(ok, fail) {
+ let password = prompt("Password?", '');
+ if (password == "rockstar") ok();
+ else fail();
+}
+
+let user = {
+ name: 'John',
+
+ login(result) {
+ alert( this.name + (result ? ' logged in' : ' failed to log in') );
+ }
+};
+
+*!*
+askPassword(?, ?); // ?
+*/!*
+```
+
+Your changes should only modify the highlighted fragment.
+
diff --git a/1-js/06-advanced-functions/10-bind/article.md b/1-js/06-advanced-functions/10-bind/article.md
index fdb07c6085..7a6e47b90a 100644
--- a/1-js/06-advanced-functions/10-bind/article.md
+++ b/1-js/06-advanced-functions/10-bind/article.md
@@ -5,13 +5,13 @@ libs:
# Function binding
-When using `setTimeout` with object methods or passing object methods along, there's a known problem: "losing `this`".
+When passing object methods as callbacks, for instance to `setTimeout`, there's a known problem: "losing `this`".
-Suddenly, `this` just stops working right. The situation is typical for novice developers, but happens with experienced ones as well.
+In this chapter we'll see the ways to fix it.
## Losing "this"
-We already know that in JavaScript it's easy to lose `this`. Once a method is passed somewhere separately from the object -- `this` is lost.
+We've already seen examples of losing `this`. Once a method is passed somewhere separately from the object -- `this` is lost.
Here's how it may happen with `setTimeout`:
@@ -37,7 +37,7 @@ let f = user.sayHi;
setTimeout(f, 1000); // lost user context
```
-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`.
+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, usually `this` just becomes `undefined`.
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?
@@ -83,10 +83,12 @@ let user = {
setTimeout(() => user.sayHi(), 1000);
-// ...within 1 second
-user = { sayHi() { alert("Another user in setTimeout!"); } };
+// ...the value of user changes within 1 second
+user = {
+ sayHi() { alert("Another user in setTimeout!"); }
+};
-// Another user in setTimeout?!?
+// Another user in setTimeout!
```
The next solution guarantees that such thing won't happen.
@@ -98,9 +100,9 @@ Functions provide a built-in method [bind](mdn:js/Function/bind) that allows to
The basic syntax is:
```js
-// more complex syntax will be little later
+// more complex syntax will come a little later
let boundFunc = func.bind(context);
-````
+```
The result of `func.bind(context)` is a special function-like "exotic object", that is callable as function and transparently passes the call to `func` setting `this=context`.
@@ -123,7 +125,7 @@ funcUser(); // John
*/!*
```
-Here `func.bind(user)` as a "bound variant" of `func`, with fixed `this=user`.
+Here `func.bind(user)` is a "bound variant" of `func`, with fixed `this=user`.
All arguments are passed to the original `func` "as is", for instance:
@@ -159,9 +161,16 @@ let user = {
let sayHi = user.sayHi.bind(user); // (*)
*/!*
+// can run it without an object
sayHi(); // Hello, John!
setTimeout(sayHi, 1000); // Hello, John!
+
+// even if the value of user changes within 1 second
+// sayHi uses the pre-bound value which is reference to the old user object
+user = {
+ sayHi() { alert("Another user in setTimeout!"); }
+};
```
In the line `(*)` we take the method `user.sayHi` and bind it to `user`. The `sayHi` is a "bound" function, that can be called alone or passed to `setTimeout` -- doesn't matter, the context will be right.
@@ -178,8 +187,8 @@ let user = {
let say = user.say.bind(user);
-say("Hello"); // Hello, John ("Hello" argument is passed to say)
-say("Bye"); // Bye, John ("Bye" is passed to say)
+say("Hello"); // Hello, John! ("Hello" argument is passed to say)
+say("Bye"); // Bye, John! ("Bye" is passed to say)
```
````smart header="Convenience method: `bindAll`"
@@ -193,11 +202,127 @@ for (let key in user) {
}
```
-JavaScript libraries also provide functions for convenient mass binding , e.g. [_.bindAll(obj)](http://lodash.com/docs#bindAll) in lodash.
+JavaScript libraries also provide functions for convenient mass binding , e.g. [_.bindAll(object, methodNames)](https://lodash.com/docs#bindAll) in lodash.
````
+## Partial functions
+
+Until now we have only been talking about binding `this`. Let's take it a step further.
+
+We can bind not only `this`, but also arguments. That's rarely done, but sometimes can be handy.
+
+The full syntax of `bind`:
+
+```js
+let bound = func.bind(context, [arg1], [arg2], ...);
+```
+
+It allows to bind context as `this` and starting arguments of the function.
+
+For instance, we have a multiplication function `mul(a, b)`:
+
+```js
+function mul(a, b) {
+ return a * b;
+}
+```
+
+Let's use `bind` to create a function `double` on its base:
+
+```js run
+function mul(a, b) {
+ return a * b;
+}
+
+*!*
+let double = mul.bind(null, 2);
+*/!*
+
+alert( double(3) ); // = mul(2, 3) = 6
+alert( double(4) ); // = mul(2, 4) = 8
+alert( double(5) ); // = mul(2, 5) = 10
+```
+
+The call to `mul.bind(null, 2)` creates a new function `double` that passes calls to `mul`, fixing `null` as the context and `2` as the first argument. Further arguments are passed "as is".
+
+That's called [partial function application](https://en.wikipedia.org/wiki/Partial_application) -- we create a new function by fixing some parameters of the existing one.
+
+Please note that we actually don't use `this` here. But `bind` requires it, so we must put in something like `null`.
+
+The function `triple` in the code below triples the value:
+
+```js run
+function mul(a, b) {
+ return a * b;
+}
+
+*!*
+let triple = mul.bind(null, 3);
+*/!*
+
+alert( triple(3) ); // = mul(3, 3) = 9
+alert( triple(4) ); // = mul(3, 4) = 12
+alert( triple(5) ); // = mul(3, 5) = 15
+```
+
+Why do we usually make a partial function?
+
+The benefit is that we can create an independent function with a readable name (`double`, `triple`). We can use it and not provide the first argument every time as it's fixed with `bind`.
+
+In other cases, partial application is useful when we have a very generic function and want a less universal variant of it for convenience.
+
+For instance, we have a function `send(from, to, text)`. Then, inside a `user` object we may want to use a partial variant of it: `sendTo(to, text)` that sends from the current user.
+
+## Going partial without context
+
+What if we'd like to fix some arguments, but not the context `this`? For example, for an object method.
+
+The native `bind` does not allow that. We can't just omit the context and jump to arguments.
+
+Fortunately, a function `partial` for binding only arguments can be easily implemented.
+
+Like this:
+
+```js run
+*!*
+function partial(func, ...argsBound) {
+ return function(...args) { // (*)
+ return func.call(this, ...argsBound, ...args);
+ }
+}
+*/!*
+
+// Usage:
+let user = {
+ firstName: "John",
+ say(time, phrase) {
+ alert(`[${time}] ${this.firstName}: ${phrase}!`);
+ }
+};
+
+// add a partial method with fixed time
+user.sayNow = partial(user.say, new Date().getHours() + ':' + new Date().getMinutes());
+
+user.sayNow("Hello");
+// Something like:
+// [10:00] John: Hello!
+```
+
+The result of `partial(func[, arg1, arg2...])` call is a wrapper `(*)` that calls `func` with:
+- Same `this` as it gets (for `user.sayNow` call it's `user`)
+- Then gives it `...argsBound` -- arguments from the `partial` call (`"10:00"`)
+- Then gives it `...args` -- arguments given to the wrapper (`"Hello"`)
+
+So easy to do it with the spread syntax, right?
+
+Also there's a ready [_.partial](https://lodash.com/docs#partial) implementation from lodash library.
+
## Summary
Method `func.bind(context, ...args)` returns a "bound variant" of function `func` that fixes the context `this` and first arguments if given.
-Usually we apply `bind` to fix `this` in an object method, so that we can pass it somewhere. For example, to `setTimeout`. There are more reasons to `bind` in the modern development, we'll meet them later.
+Usually we apply `bind` to fix `this` for an object method, so that we can pass it somewhere. For example, to `setTimeout`.
+
+When we fix some arguments of an existing function, the resulting (less universal) function is called *partially applied* or *partial*.
+
+Partials are convenient when we don't want to repeat the same argument over and over again. Like if we have a `send(from, to)` function, and `from` should always be the same for our task, we can get a partial and go on with it.
diff --git a/1-js/06-advanced-functions/11-currying-partials/1-ask-currying/task.md b/1-js/06-advanced-functions/11-currying-partials/1-ask-currying/task.md
deleted file mode 100644
index f8b83d7a20..0000000000
--- a/1-js/06-advanced-functions/11-currying-partials/1-ask-currying/task.md
+++ /dev/null
@@ -1,34 +0,0 @@
-importance: 5
-
----
-
-# Partial application for login
-
-The task is a little more complex variant of .
-
-The `user` object was modified. Now instead of two functions `loginOk/loginFail`, it has a single function `user.login(true/false)`.
-
-What to pass `askPassword` in the code below, so that it calls `user.login(true)` as `ok` and `user.login(false)` as `fail`?
-
-```js
-function askPassword(ok, fail) {
- let password = prompt("Password?", '');
- if (password == "rockstar") ok();
- else fail();
-}
-
-let user = {
- name: 'John',
-
- login(result) {
- alert( this.name + (result ? ' logged in' : ' failed to log in') );
- }
-};
-
-*!*
-askPassword(?, ?); // ?
-*/!*
-```
-
-Your changes should only modify the highlighted fragment.
-
diff --git a/1-js/06-advanced-functions/11-currying-partials/article.md b/1-js/06-advanced-functions/11-currying-partials/article.md
deleted file mode 100644
index 310e48305c..0000000000
--- a/1-js/06-advanced-functions/11-currying-partials/article.md
+++ /dev/null
@@ -1,308 +0,0 @@
-libs:
- - lodash
-
----
-
-# Currying and partials
-
-Until now we have only been talking about binding `this`. Let's take it a step further.
-
-We can bind not only `this`, but also arguments. That's rarely done, but sometimes can be handy.
-
-The full syntax of `bind`:
-
-```js
-let bound = func.bind(context, arg1, arg2, ...);
-```
-
-It allows to bind context as `this` and starting arguments of the function.
-
-For instance, we have a multiplication function `mul(a, b)`:
-
-```js
-function mul(a, b) {
- return a * b;
-}
-```
-
-Let's use `bind` to create a function `double` on its base:
-
-```js run
-function mul(a, b) {
- return a * b;
-}
-
-*!*
-let double = mul.bind(null, 2);
-*/!*
-
-alert( double(3) ); // = mul(2, 3) = 6
-alert( double(4) ); // = mul(2, 4) = 8
-alert( double(5) ); // = mul(2, 5) = 10
-```
-
-The call to `mul.bind(null, 2)` creates a new function `double` that passes calls to `mul`, fixing `null` as the context and `2` as the first argument. Further arguments are passed "as is".
-
-That's called [partial function application](https://en.wikipedia.org/wiki/Partial_application) -- we create a new function by fixing some parameters of the existing one.
-
-Please note that here we actually don't use `this` here. But `bind` requires it, so we must put in something like `null`.
-
-The function `triple` in the code below triples the value:
-
-```js run
-function mul(a, b) {
- return a * b;
-}
-
-*!*
-let triple = mul.bind(null, 3);
-*/!*
-
-alert( triple(3) ); // = mul(3, 3) = 9
-alert( triple(4) ); // = mul(3, 4) = 12
-alert( triple(5) ); // = mul(3, 5) = 15
-```
-
-Why do we usually make a partial function?
-
-Here our benefit is that we created an independent function with a readable name (`double`, `triple`). We can use it and don't write the first argument of every time, cause it's fixed with `bind`.
-
-In other cases, partial application is useful when we have a very generic function, and want a less universal variant of it for convenience.
-
-For instance, we have a function `send(from, to, text)`. Then, inside a `user` object we may want to use a partial variant of it: `sendTo(to, text)` that sends from the current user.
-
-## Going partial without context
-
-What if we'd like to fix some arguments, but not bind `this`?
-
-The native `bind` does not allow that. We can't just omit the context and jump to arguments.
-
-Fortunately, a `partial` function for binding only arguments can be easily implemented.
-
-Like this:
-
-```js run
-*!*
-function partial(func, ...argsBound) {
- return function(...args) { // (*)
- return func.call(this, ...argsBound, ...args);
- }
-}
-*/!*
-
-// Usage:
-let user = {
- firstName: "John",
- say(time, phrase) {
- alert(`[${time}] ${this.firstName}: ${phrase}!`);
- }
-};
-
-// add a partial method that says something now by fixing the first argument
-user.sayNow = partial(user.say, new Date().getHours() + ':' + new Date().getMinutes());
-
-user.sayNow("Hello");
-// Something like:
-// [10:00] John: Hello!
-```
-
-The result of `partial(func[, arg1, arg2...])` call is a wrapper `(*)` that calls `func` with:
-- Same `this` as it gets (for `user.sayNow` call it's `user`)
-- Then gives it `...argsBound` -- arguments from the `partial` call (`"10:00"`)
-- Then gives it `...args` -- arguments given to the wrapper (`"Hello"`)
-
-So easy to do it with the spread operator, right?
-
-Also there's a ready [_.partial](https://lodash.com/docs#partial) implementation from lodash library.
-
-## Currying
-
-Sometimes people mix up partial function application mentioned above with another thing named "currying". That's another interesting technique of working with functions that we just have to mention here.
-
-[Currying](https://en.wikipedia.org/wiki/Currying) is translating a function from callable as `f(a, b, c)` into callable as `f(a)(b)(c)`.
-
-Literally, currying is a transformation of functions: from one way of calling into another. In JavaScript, we usually make a wrapper to keep the original function.
-
-Currying doesn't call a function. It just transforms it. We'll see use cases soon.
-
-Let's make `curry` function that performs currying for two-argument functions. In other words, `curry(f)` for two-argument `f(a, b)` translates it into `f(a)(b)`
-
-```js run
-*!*
-function curry(f) { // curry(f) does the currying transform
- return function(a) {
- return function(b) {
- return f(a, b);
- };
- };
-}
-*/!*
-
-// usage
-function sum(a, b) {
- return a + b;
-}
-
-let carriedSum = curry(sum);
-
-alert( carriedSum(1)(2) ); // 3
-```
-
-As you can see, the implementation is a series of wrappers.
-
-- The result of `curry(func)` is a wrapper `function(a)`.
-- When it is called like `sum(1)`, the argument is saved in the Lexical Environment, and a new wrapper is returned `function(b)`.
-- Then `sum(1)(2)` finally calls `function(b)` providing `2`, and it passes the call to the original multi-argument `sum`.
-
-More advanced implementations of currying like [_.curry](https://lodash.com/docs#curry) from lodash library do something more sophisticated. They return a wrapper that allows a function to be called normally when all arguments are supplied *or* returns a partial otherwise.
-
-```js
-function curry(f) {
- return function(...args) {
- // if args.length == f.length (as many arguments as f has),
- // then pass the call to f
- // otherwise return a partial function that fixes args as first arguments
- };
-}
-```
-
-## Currying? What for?
-
-To understand the benefits we definitely need a worthy real-life example. Advanced currying allows the function to be both callable normally and get partials.
-
-For instance, we have the logging function `log(date, importance, message)` that formats and outputs the information. In real projects such functions also have many other useful features like: sending it over the network or filtering:
-
-```js
-function log(date, importance, message) {
- alert(`[${date.getHours()}:${date.getMinutes()}] [${importance}] ${message}`);
-}
-```
-
-Let's curry it!
-
-```js
-log = _.curry(log);
-```
-
-After that `log` still works the normal way:
-
-```js
-log(new Date(), "DEBUG", "some debug");
-```
-
-...But also can be called in the curried form:
-
-```js
-log(new Date())("DEBUG")("some debug"); // log(a)(b)(c)
-```
-
-Let's get a convenience function for today's logs:
-
-```js
-// todayLog will be the partial of log with fixed first argument
-let todayLog = log(new Date());
-
-// use it
-todayLog("INFO", "message"); // [HH:mm] INFO message
-```
-
-And now a convenience function for today's debug messages:
-
-```js
-let todayDebug = todayLog("DEBUG");
-
-todayDebug("message"); // [HH:mm] DEBUG message
-```
-
-So:
-1. We didn't lose anything after currying: `log` is still callable normally.
-2. We were able to generate partial functions that are convenient in many cases.
-
-## Advanced curry implementation
-
-In case you're interested, here's the "advanced" curry implementation that we could use above, it's pretty short:
-
-```js run
-function curry(func) {
-
- return function curried(...args) {
- if (args.length >= func.length) {
- return func.apply(this, args);
- } else {
- return function(...args2) {
- return curried.apply(this, args.concat(args2));
- }
- }
- };
-
-}
-
-function sum(a, b, c) {
- return a + b + c;
-}
-
-let curriedSum = curry(sum);
-
-// still callable normally
-alert( curriedSum(1, 2, 3) ); // 6
-
-// get the partial with curried(1) and call it with 2 other arguments
-alert( curriedSum(1)(2,3) ); // 6
-
-// full curried form
-alert( curriedSum(1)(2)(3) ); // 6
-```
-
-The new `curry` may look complicated, but it's actually easy to understand.
-
-The result of `curry(func)` is the wrapper `curried` that looks like this:
-
-```js
-// func is the function to transform
-function curried(...args) {
- if (args.length >= func.length) { // (1)
- return func.apply(this, args);
- } else {
- return function pass(...args2) { // (2)
- return curried.apply(this, args.concat(args2));
- }
- }
-};
-```
-
-When we run it, there are two branches:
-
-1. Call now: if passed `args` count is the same as the original function has in its definition (`func.length`) or longer, then just pass the call to it.
-2. Get a partial: otherwise, `func` is not called yet. Instead, another wrapper `pass` is returned, that will re-apply `curried` providing previous arguments together with the new ones. Then on a new call, again, we'll get either a new partial (if not enough arguments) or, finally, the result.
-
-For instance, let's see what happens in the case of `sum(a, b, c)`. Three arguments, so `sum.length = 3`.
-
-For the call `curried(1)(2)(3)`:
-
-1. The first call `curried(1)` remembers `1` in its Lexical Environment, and returns a wrapper `pass`.
-2. The wrapper `pass` is called with `(2)`: it takes previous args (`1`), concatenates them with what it got `(2)` and calls `curried(1, 2)` with them together.
-
- As the argument count is still less than 3, `curry` returns `pass`.
-3. The wrapper `pass` is called again with `(3)`, for the next call `pass(3)` takes previous args (`1`, `2`) and adds `3` to them, making the call `curried(1, 2, 3)` -- there are `3` arguments at last, they are given to the original function.
-
-If that's still not obvious, just trace the calls sequence in your mind or on the paper.
-
-```smart header="Fixed-length functions only"
-The currying requires the function to have a known fixed number of arguments.
-```
-
-```smart header="A little more than currying"
-By definition, currying should convert `sum(a, b, c)` into `sum(a)(b)(c)`.
-
-But most implementations of currying in JavaScript are advanced, as described: they also keep the function callable in the multi-argument variant.
-```
-
-## Summary
-
-- When we fix some arguments of an existing function, the resulting (less universal) function is called *a partial*. We can use `bind` to get a partial, but there are other ways also.
-
- Partials are convenient when we don't want to repeat the same argument over and over again. Like if we have a `send(from, to)` function, and `from` should always be the same for our task, we can get a partial and go on with it.
-
-- *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.
-
- 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)`.
diff --git a/1-js/06-advanced-functions/12-arrow-functions/article.md b/1-js/06-advanced-functions/12-arrow-functions/article.md
index 1ade1a4192..8730277ad7 100644
--- a/1-js/06-advanced-functions/12-arrow-functions/article.md
+++ b/1-js/06-advanced-functions/12-arrow-functions/article.md
@@ -2,9 +2,9 @@
Let's revisit arrow functions.
-Arrow functions are not just a "shorthand" for writing small stuff.
+Arrow functions are not just a "shorthand" for writing small stuff. They have some very specific and useful features.
-JavaScript is full of situations where we need to write a small function, that's executed somewhere else.
+JavaScript is full of situations where we need to write a small function that's executed somewhere else.
For instance:
@@ -14,7 +14,7 @@ For instance:
It's in the very spirit of JavaScript to create a function and pass it somewhere.
-And in such functions we usually don't want to leave the current context.
+And in such functions we usually don't want to leave the current context. That's where arrow functions come in handy.
## Arrow functions have no "this"
@@ -52,7 +52,7 @@ let group = {
*!*
this.students.forEach(function(student) {
// Error: Cannot read property 'title' of undefined
- alert(this.title + ': ' + student)
+ alert(this.title + ': ' + student);
});
*/!*
}
@@ -87,7 +87,7 @@ For instance, `defer(f, ms)` gets a function and returns a wrapper around it tha
```js run
function defer(f, ms) {
return function() {
- setTimeout(() => f.apply(this, arguments), ms)
+ setTimeout(() => f.apply(this, arguments), ms);
};
}
@@ -118,9 +118,9 @@ Here we had to create additional variables `args` and `ctx` so that the function
Arrow functions:
-- Do not have `this`.
-- Do not have `arguments`.
-- Can't be called with `new`.
-- (They also don't have `super`, but we didn't study it. Will be in the chapter ).
+- Do not have `this`
+- Do not have `arguments`
+- Can't be called with `new`
+- They also don't have `super`, but we didn't study it yet. We will on the chapter
-That's because they are meant for short pieces of code that do not have their own "context", but rather works in the current one. And they really shine in that use case.
+That's because they are meant for short pieces of code that do not have their own "context", but rather work in the current one. And they really shine in that use case.
diff --git a/1-js/07-object-properties/01-property-descriptors/article.md b/1-js/07-object-properties/01-property-descriptors/article.md
index c44e565025..0a945b377b 100644
--- a/1-js/07-object-properties/01-property-descriptors/article.md
+++ b/1-js/07-object-properties/01-property-descriptors/article.md
@@ -3,7 +3,7 @@
As we know, objects can store properties.
-Till now, a property was a simple "key-value" pair to us. But an object property is actually a more flexible and powerful thing.
+Until now, a property was a simple "key-value" pair to us. But an object property is actually a more flexible and powerful thing.
In this chapter we'll study additional configuration options, and in the next we'll see how to invisibly turn them into getter/setter functions.
@@ -11,7 +11,7 @@ In this chapter we'll study additional configuration options, and in the next we
Object properties, besides a **`value`**, have three special attributes (so-called "flags"):
-- **`writable`** -- if `true`, can be changed, otherwise it's read-only.
+- **`writable`** -- if `true`, the value can be changed, otherwise it's read-only.
- **`enumerable`** -- if `true`, then listed in loops, otherwise not listed.
- **`configurable`** -- if `true`, the property can be deleted and these attributes can be modified, otherwise not.
@@ -19,7 +19,7 @@ We didn't see them yet, because generally they do not show up. When we create a
First, let's see how to get those flags.
-The method [Object.getOwnPropertyDescriptor](mdn:js/Object/getOwnPropertyDescriptor) allows to query the *full* information about a property.
+The method [Object.getOwnPropertyDescriptor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptor) allows to query the *full* information about a property.
The syntax is:
```js
@@ -54,7 +54,7 @@ alert( JSON.stringify(descriptor, null, 2 ) );
*/
```
-To change the flags, we can use [Object.defineProperty](mdn:js/Object/defineProperty).
+To change the flags, we can use [Object.defineProperty](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty).
The syntax is:
@@ -63,10 +63,10 @@ Object.defineProperty(obj, propertyName, descriptor)
```
`obj`, `propertyName`
-: The object and property to work on.
+: The object and its property to apply the descriptor.
`descriptor`
-: Property descriptor to apply.
+: Property descriptor object to apply.
If the property exists, `defineProperty` updates its flags. Otherwise, it creates the property with the given value and flags; in that case, if a flag is not supplied, it is assumed `false`.
@@ -100,9 +100,9 @@ Compare it with "normally created" `user.name` above: now all flags are falsy. I
Now let's see effects of the flags by example.
-## Read-only
+## Non-writable
-Let's make `user.name` read-only by changing `writable` flag:
+Let's make `user.name` non-writable (can't be reassigned) by changing `writable` flag:
```js run
let user = {
@@ -116,36 +116,39 @@ Object.defineProperty(user, "name", {
});
*!*
-user.name = "Pete"; // Error: Cannot assign to read only property 'name'...
+user.name = "Pete"; // Error: Cannot assign to read only property 'name'
*/!*
```
Now no one can change the name of our user, unless they apply their own `defineProperty` to override ours.
-Here's the same operation, but for the case when a property doesn't exist:
+```smart header="Errors appear only in strict mode"
+In non-strict mode, no errors occur when writing to non-writable properties and such. But the operation still won't succeed. Flag-violating actions are just silently ignored in non-strict.
+```
+
+Here's the same example, but the property is created from scratch:
```js run
let user = { };
Object.defineProperty(user, "name", {
*!*
- value: "Pete",
- // for new properties need to explicitly list what's true
+ value: "John",
+ // for new properties we need to explicitly list what's true
enumerable: true,
configurable: true
*/!*
});
-alert(user.name); // Pete
-user.name = "Alice"; // Error
+alert(user.name); // John
+user.name = "Pete"; // Error
```
-
## Non-enumerable
Now let's add a custom `toString` to `user`.
-Normally, a built-in `toString` for objects is non-enumerable, it does not show up in `for..in`. But if we add `toString` of our own, then by default it shows up in `for..in`, like this:
+Normally, a built-in `toString` for objects is non-enumerable, it does not show up in `for..in`. But if we add a `toString` of our own, then by default it shows up in `for..in`, like this:
```js run
let user = {
@@ -159,7 +162,7 @@ let user = {
for (let key in user) alert(key); // name, toString
```
-If we don't like it, then we can set `enumerable:false`. Then it won't appear in `for..in` loop, just like the built-in one:
+If we don't like it, then we can set `enumerable:false`. Then it won't appear in a `for..in` loop, just like the built-in one:
```js run
let user = {
@@ -191,9 +194,9 @@ alert(Object.keys(user)); // name
The non-configurable flag (`configurable:false`) is sometimes preset for built-in objects and properties.
-A non-configurable property can not be deleted or altered with `defineProperty`.
+A non-configurable property can't be deleted, its attributes can't be modified.
-For instance, `Math.PI` is read-only, non-enumerable and non-configurable:
+For instance, `Math.PI` is non-writable, non-enumerable and non-configurable:
```js run
let descriptor = Object.getOwnPropertyDescriptor(Math, 'PI');
@@ -211,41 +214,67 @@ alert( JSON.stringify(descriptor, null, 2 ) );
So, a programmer is unable to change the value of `Math.PI` or overwrite it.
```js run
-Math.PI = 3; // Error
+Math.PI = 3; // Error, because it has writable: false
// delete Math.PI won't work either
```
-Making a property non-configurable is a one-way road. We cannot change it back, because `defineProperty` doesn't work on non-configurable properties.
+We also can't change `Math.PI` to be `writable` again:
+
+```js run
+// Error, because of configurable: false
+Object.defineProperty(Math, "PI", { writable: true });
+```
+
+There's absolutely nothing we can do with `Math.PI`.
-Here we are making `user.name` a "forever sealed" constant:
+Making a property non-configurable is a one-way road. We cannot change it back with `defineProperty`.
+
+**Please note: `configurable: false` prevents changes of property flags and its deletion, while allowing to change its value.**
+
+Here `user.name` is non-configurable, but we can still change it (as it's writable):
```js run
-let user = { };
+let user = {
+ name: "John"
+};
+
+Object.defineProperty(user, "name", {
+ configurable: false
+});
+
+user.name = "Pete"; // works fine
+delete user.name; // Error
+```
+
+And here we make `user.name` a "forever sealed" constant, just like the built-in `Math.PI`:
+
+```js run
+let user = {
+ name: "John"
+};
Object.defineProperty(user, "name", {
- value: "John",
writable: false,
configurable: false
});
-*!*
// won't be able to change user.name or its flags
// all this won't work:
-// user.name = "Pete"
-// delete user.name
-// defineProperty(user, "name", ...)
-Object.defineProperty(user, "name", {writable: true}); // Error
-*/!*
+user.name = "Pete";
+delete user.name;
+Object.defineProperty(user, "name", { value: "Pete" });
```
-```smart header="Errors appear only in use strict"
-In the non-strict mode, no errors occur when writing to read-only properties and such. But the operation still won't succeed. Flag-violating actions are just silently ignored in non-strict.
+```smart header="The only attribute change possible: writable true -> false"
+There's a minor exception about changing flags.
+
+We can change `writable: true` to `false` for a non-configurable property, thus preventing its value modification (to add another layer of protection). Not the other way around though.
```
## Object.defineProperties
-There's a method [Object.defineProperties(obj, descriptors)](mdn:js/Object/defineProperties) that allows to define many properties at once.
+There's a method [Object.defineProperties(obj, descriptors)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties) that allows to define many properties at once.
The syntax is:
@@ -271,7 +300,7 @@ So, we can set many properties at once.
## Object.getOwnPropertyDescriptors
-To get all property descriptors at once, we can use the method [Object.getOwnPropertyDescriptors(obj)](mdn:js/Object/getOwnPropertyDescriptors).
+To get all property descriptors at once, we can use the method [Object.getOwnPropertyDescriptors(obj)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptors).
Together with `Object.defineProperties` it can be used as a "flags-aware" way of cloning an object:
@@ -289,7 +318,7 @@ for (let key in user) {
...But that does not copy flags. So if we want a "better" clone then `Object.defineProperties` is preferred.
-Another difference is that `for..in` ignores symbolic properties, but `Object.getOwnPropertyDescriptors` returns *all* property descriptors including symbolic ones.
+Another difference is that `for..in` ignores symbolic and non-enumerable properties, but `Object.getOwnPropertyDescriptors` returns *all* property descriptors including symbolic and non-enumerable ones.
## Sealing an object globally
@@ -297,24 +326,24 @@ Property descriptors work at the level of individual properties.
There are also methods that limit access to the *whole* object:
-[Object.preventExtensions(obj)](mdn:js/Object/preventExtensions)
-: Forbids to add properties to the object.
+[Object.preventExtensions(obj)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/preventExtensions)
+: Forbids the addition of new properties to the object.
-[Object.seal(obj)](mdn:js/Object/seal)
-: Forbids to add/remove properties, sets for all existing properties `configurable: false`.
+[Object.seal(obj)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/seal)
+: Forbids adding/removing of properties. Sets `configurable: false` for all existing properties.
-[Object.freeze(obj)](mdn:js/Object/freeze)
-: Forbids to add/remove/change properties, sets for all existing properties `configurable: false, writable: false`.
+[Object.freeze(obj)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze)
+: Forbids adding/removing/changing of properties. Sets `configurable: false, writable: false` for all existing properties.
And also there are tests for them:
-[Object.isExtensible(obj)](mdn:js/Object/isExtensible)
+[Object.isExtensible(obj)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isExtensible)
: Returns `false` if adding properties is forbidden, otherwise `true`.
-[Object.isSealed(obj)](mdn:js/Object/isSealed)
+[Object.isSealed(obj)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isSealed)
: Returns `true` if adding/removing properties is forbidden, and all existing properties have `configurable: false`.
-[Object.isFrozen(obj)](mdn:js/Object/isFrozen)
+[Object.isFrozen(obj)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isFrozen)
: Returns `true` if adding/removing/changing properties is forbidden, and all current properties are `configurable: false, writable: false`.
These methods are rarely used in practice.
diff --git a/1-js/07-object-properties/02-property-accessors/article.md b/1-js/07-object-properties/02-property-accessors/article.md
index 43cd5ae6d7..c2aa35d53a 100644
--- a/1-js/07-object-properties/02-property-accessors/article.md
+++ b/1-js/07-object-properties/02-property-accessors/article.md
@@ -1,11 +1,11 @@
# Property getters and setters
-There are two kinds of properties.
+There are two kinds of object properties.
-The first kind is *data properties*. We already know how to work with them. Actually, all properties that we've been using till now were data properties.
+The first kind is *data properties*. We already know how to work with them. All properties that we've been using until now were data properties.
-The second type of properties is something new. It's *accessor properties*. They are essentially functions that work on getting and setting a value, but look like regular properties to an external code.
+The second type of property is something new. It's an *accessor property*. They are essentially functions that execute on getting and setting a value, but look like regular properties to an external code.
## Getters and setters
@@ -27,14 +27,14 @@ The getter works when `obj.propName` is read, the setter -- when it is assigned.
For instance, we have a `user` object with `name` and `surname`:
-```js run
+```js
let user = {
name: "John",
surname: "Smith"
};
```
-Now we want to add a "fullName" property, that should be "John Smith". Of course, we don't want to copy-paste existing information, so we can implement it as an accessor:
+Now we want to add a `fullName` property, that should be `"John Smith"`. Of course, we don't want to copy-paste existing information, so we can implement it as an accessor:
```js run
let user = {
@@ -53,9 +53,21 @@ alert(user.fullName); // John Smith
*/!*
```
-From outside, an accessor property looks like a regular one. That's the idea of accessor properties. We don't *call* `user.fullName` as a function, we *read* it normally: the getter runs behind the scenes.
+From the outside, an accessor property looks like a regular one. That's the idea of accessor properties. We don't *call* `user.fullName` as a function, we *read* it normally: the getter runs behind the scenes.
+
+As of now, `fullName` has only a getter. If we attempt to assign `user.fullName=`, there will be an error:
-As of now, `fullName` has only a getter. If we attempt to assign `user.fullName=`, there will be an error.
+```js run
+let user = {
+ get fullName() {
+ return `...`;
+ }
+};
+
+*!*
+user.fullName = "Test"; // Error (property has only a getter)
+*/!*
+```
Let's fix it by adding a setter for `user.fullName`:
@@ -82,25 +94,15 @@ alert(user.name); // Alice
alert(user.surname); // Cooper
```
-Now we have a "virtual" property. It is readable and writable, but in fact does not exist.
-
-```smart header="Accessor properties are only accessible with get/set"
-Once a property is defined with `get prop()` or `set prop()`, it's an accessor property, not a data properety any more.
-
-- If there's a getter -- we can read `object.prop`, othrewise we can't.
-- If there's a setter -- we can set `object.prop=...`, othrewise we can't.
-
-And in either case we can't `delete` an accessor property.
-```
-
+As the result, we have a "virtual" property `fullName`. It is readable and writable.
## Accessor descriptors
-Descriptors for accessor properties are different -- as compared with data properties.
+Descriptors for accessor properties are different from those for data properties.
-For accessor properties, there is no `value` and `writable`, but instead there are `get` and `set` functions.
+For accessor properties, there is no `value` or `writable`, but instead there are `get` and `set` functions.
-So an accessor descriptor may have:
+That is, an accessor descriptor may have:
- **`get`** -- a function without arguments, that works when a property is read,
- **`set`** -- a function with one argument, that is called when the property is set,
@@ -132,7 +134,7 @@ alert(user.fullName); // John Smith
for(let key in user) alert(key); // name, surname
```
-Please note once again that a property can be either an accessor or a data property, not both.
+Please note that a property can be either an accessor (has `get/set` methods) or a data property (has a `value`), not both.
If we try to supply both `get` and `value` in the same descriptor, there will be an error:
@@ -151,9 +153,9 @@ Object.defineProperty({}, 'prop', {
## Smarter getters/setters
-Getters/setters can be used as wrappers over "real" property values to gain more control over them.
+Getters/setters can be used as wrappers over "real" property values to gain more control over operations with them.
-For instance, if we want to forbid too short names for `user`, we can store `name` in a special property `_name`. And filter assignments in the setter:
+For instance, if we want to forbid too short names for `user`, we can have a setter `name` and keep the value in a separate property `_name`:
```js run
let user = {
@@ -176,14 +178,16 @@ alert(user.name); // Pete
user.name = ""; // Name is too short...
```
-Technically, the external code may still access the name directly by using `user._name`. But there is a widely known agreement that properties starting with an underscore `"_"` are internal and should not be touched from outside the object.
+So, the name is stored in `_name` property, and the access is done via getter and setter.
+
+Technically, external code is able to access the name directly by using `user._name`. But there is a widely known convention that properties starting with an underscore `"_"` are internal and should not be touched from outside the object.
## Using for compatibility
-One of the great ideas behind getters and setters -- they allow to take control over a "normal" data property and tweak it at any moment.
+One of the great uses of accessors is that they allow to take control over a "regular" data property at any moment by replacing it with a getter and a setter and tweak its behavior.
-For instance, we started implementing user objects using data properties `name` and `age`:
+Imagine we started implementing user objects using data properties `name` and `age`:
```js
function User(name, age) {
@@ -209,9 +213,11 @@ let john = new User("John", new Date(1992, 6, 1));
Now what to do with the old code that still uses `age` property?
-We can try to find all such places and fix them, but that takes time and can be hard to do if that code is written by other people. And besides, `age` is a nice thing to have in `user`, right? In some places it's just what we want.
+We can try to find all such places and fix them, but that takes time and can be hard to do if that code is used by many other people. And besides, `age` is a nice thing to have in `user`, right?
+
+Let's keep it.
-Adding a getter for `age` mitigates the problem:
+Adding a getter for `age` solves the problem:
```js run no-beautify
function User(name, birthday) {
diff --git a/1-js/08-prototypes/01-prototype-inheritance/2-search-algorithm/task.md b/1-js/08-prototypes/01-prototype-inheritance/2-search-algorithm/task.md
index 002b24b8a2..bc2db47fed 100644
--- a/1-js/08-prototypes/01-prototype-inheritance/2-search-algorithm/task.md
+++ b/1-js/08-prototypes/01-prototype-inheritance/2-search-algorithm/task.md
@@ -6,7 +6,7 @@ importance: 5
The task has two parts.
-We have an object:
+Given the following objects:
```js
let head = {
diff --git a/1-js/08-prototypes/01-prototype-inheritance/3-proto-and-this/solution.md b/1-js/08-prototypes/01-prototype-inheritance/3-proto-and-this/solution.md
index c7d147b9c7..4d6ea2653c 100644
--- a/1-js/08-prototypes/01-prototype-inheritance/3-proto-and-this/solution.md
+++ b/1-js/08-prototypes/01-prototype-inheritance/3-proto-and-this/solution.md
@@ -3,4 +3,5 @@
That's because `this` is an object before the dot, so `rabbit.eat()` modifies `rabbit`.
Property lookup and execution are two different things.
-The method `rabbit.eat` is first found in the prototype, then executed with `this=rabbit`
+
+The method `rabbit.eat` is first found in the prototype, then executed with `this=rabbit`.
diff --git a/1-js/08-prototypes/01-prototype-inheritance/3-proto-and-this/task.md b/1-js/08-prototypes/01-prototype-inheritance/3-proto-and-this/task.md
index b37499bad5..ed8482c072 100644
--- a/1-js/08-prototypes/01-prototype-inheritance/3-proto-and-this/task.md
+++ b/1-js/08-prototypes/01-prototype-inheritance/3-proto-and-this/task.md
@@ -2,7 +2,7 @@ importance: 5
---
-# Where it writes?
+# Where does it write?
We have `rabbit` inheriting from `animal`.
diff --git a/1-js/08-prototypes/01-prototype-inheritance/4-hamster-proto/solution.md b/1-js/08-prototypes/01-prototype-inheritance/4-hamster-proto/solution.md
index fad4b88607..c141b2ecdc 100644
--- a/1-js/08-prototypes/01-prototype-inheritance/4-hamster-proto/solution.md
+++ b/1-js/08-prototypes/01-prototype-inheritance/4-hamster-proto/solution.md
@@ -10,7 +10,7 @@ Let's look carefully at what's going on in the call `speedy.eat("apple")`.
So all hamsters share a single stomach!
-Every time the `stomach` is taken from the prototype, then `stomach.push` modifies it "at place".
+Both for `lazy.stomach.push(...)` and `speedy.stomach.push()`, the property `stomach` is found in the prototype (as it's not in the object itself), then the new data is pushed into it.
Please note that such thing doesn't happen in case of a simple assignment `this.stomach=`:
@@ -44,7 +44,7 @@ alert( lazy.stomach ); //
Now all works fine, because `this.stomach=` does not perform a lookup of `stomach`. The value is written directly into `this` object.
-Also we can totally evade the problem by making sure that each hamster has their own stomach:
+Also we can totally avoid the problem by making sure that each hamster has their own stomach:
```js run
let hamster = {
@@ -77,4 +77,4 @@ alert( speedy.stomach ); // apple
alert( lazy.stomach ); //
```
-As a common solution, all properties that describe the state of a particular object, like `stomach` above, are usually written into that object. That prevents such problems.
+As a common solution, all properties that describe the state of a particular object, like `stomach` above, should be written into that object. That prevents such problems.
diff --git a/1-js/08-prototypes/01-prototype-inheritance/4-hamster-proto/task.md b/1-js/08-prototypes/01-prototype-inheritance/4-hamster-proto/task.md
index 6f9fb279ec..50171123d4 100644
--- a/1-js/08-prototypes/01-prototype-inheritance/4-hamster-proto/task.md
+++ b/1-js/08-prototypes/01-prototype-inheritance/4-hamster-proto/task.md
@@ -2,11 +2,11 @@ importance: 5
---
-# Why two hamsters are full?
+# Why are both hamsters full?
We have two hamsters: `speedy` and `lazy` inheriting from the general `hamster` object.
-When we feed one of them, the other one is also full. Why? How to fix it?
+When we feed one of them, the other one is also full. Why? How can we fix it?
```js run
let hamster = {
diff --git a/1-js/08-prototypes/01-prototype-inheritance/article.md b/1-js/08-prototypes/01-prototype-inheritance/article.md
index 1641de236c..ef6c7ffebd 100644
--- a/1-js/08-prototypes/01-prototype-inheritance/article.md
+++ b/1-js/08-prototypes/01-prototype-inheritance/article.md
@@ -10,13 +10,13 @@ For instance, we have a `user` object with its properties and methods, and want
In JavaScript, objects have a special hidden property `[[Prototype]]` (as named in the specification), that is either `null` or references another object. That object is called "a prototype":
-
+
-That `[[Prototype]]` has a "magical" meaning. When we want to read a property from `object`, and it's missing, JavaScript automatically takes it from the prototype. In programming, such thing is called "prototypal inheritance". Many cool language features and programming techniques are based on it.
+When we read a property from `object`, and it's missing, JavaScript automatically takes it from the prototype. In programming, this is called "prototypal inheritance". And soon we'll study many examples of such inheritance, as well as cooler language features built upon it.
The property `[[Prototype]]` is internal and hidden, but there are many ways to set it.
-One of them is to use `__proto__`, like this:
+One of them is to use the special name `__proto__`, like this:
```js run
let animal = {
@@ -27,23 +27,15 @@ let rabbit = {
};
*!*
-rabbit.__proto__ = animal;
+rabbit.__proto__ = animal; // sets rabbit.[[Prototype]] = animal
*/!*
```
-```smart header="`__proto__` is a historical getter/setter for `[[Prototype]]`"
-Please note that `__proto__` is *not the same* as `[[Prototype]]`. That's a getter/setter for it.
-
-It exists for historical reasons, in modern language it is replaced with functions `Object.getPrototypeOf/Object.setPrototypeOf` that also get/set the prototype. We'll study the reasons for that and these functions later.
-
-By the specification, `__proto__` must only be supported by browsers, but in fact all environments including server-side support it. For now, as `__proto__` notation is a little bit more intuitively obvious, we'll use it in the examples.
-```
-
-If we look for a property in `rabbit`, and it's missing, JavaScript automatically takes it from `animal`.
+Now if we read a property from `rabbit`, and it's missing, JavaScript will automatically take it from `animal`.
For instance:
-```js run
+```js
let animal = {
eats: true
};
@@ -62,11 +54,11 @@ alert( rabbit.eats ); // true (**)
alert( rabbit.jumps ); // true
```
-Here the line `(*)` sets `animal` to be a prototype of `rabbit`.
+Here the line `(*)` sets `animal` to be the prototype of `rabbit`.
Then, when `alert` tries to read property `rabbit.eats` `(**)`, it's not in `rabbit`, so JavaScript follows the `[[Prototype]]` reference and finds it in `animal` (look from the bottom up):
-
+
Here we can say that "`animal` is the prototype of `rabbit`" or "`rabbit` prototypically inherits from `animal`".
@@ -97,11 +89,10 @@ rabbit.walk(); // Animal walk
The method is automatically taken from the prototype, like this:
-
+
The prototype chain can be longer:
-
```js run
let animal = {
eats: true,
@@ -129,15 +120,29 @@ longEar.walk(); // Animal walk
alert(longEar.jumps); // true (from rabbit)
```
-
+
+
+Now if we read something from `longEar`, and it's missing, JavaScript will look for it in `rabbit`, and then in `animal`.
-There are actually only two limitations:
+There are only two limitations:
1. The references can't go in circles. JavaScript will throw an error if we try to assign `__proto__` in a circle.
-2. The value of `__proto__` can be either an object or `null`, other types (like primitives) are ignored.
+2. The value of `__proto__` can be either an object or `null`. Other types are ignored.
Also it may be obvious, but still: there can be only one `[[Prototype]]`. An object may not inherit from two others.
+```smart header="`__proto__` is a historical getter/setter for `[[Prototype]]`"
+It's a common mistake of novice developers not to know the difference between these two.
+
+Please note that `__proto__` is *not the same* as the internal `[[Prototype]]` property. It's a getter/setter for `[[Prototype]]`. Later we'll see situations where it matters, for now let's just keep it in mind, as we build our understanding of JavaScript language.
+
+The `__proto__` property is a bit outdated. It exists for historical reasons, modern JavaScript suggests that we should use `Object.getPrototypeOf/Object.setPrototypeOf` functions instead that get/set the prototype. We'll also cover these functions later.
+
+By the specification, `__proto__` must only be supported by browsers. In fact though, all environments including server-side support `__proto__`, so we're quite safe using it.
+
+As the `__proto__` notation is a bit more intuitively obvious, we use it in the examples.
+```
+
## Writing doesn't use prototype
The prototype is only used for reading properties.
@@ -169,9 +174,9 @@ rabbit.walk(); // Rabbit! Bounce-bounce!
From now on, `rabbit.walk()` call finds the method immediately in the object and executes it, without using the prototype:
-
+
-That's for data properties only, not for accessors. If a property is a getter/setter, then it behaves like a function: getters/setters are looked up in the prototype.
+Accessor properties are an exception, as assignment is handled by a setter function. So writing to such a property is actually the same as calling a function.
For that reason `admin.fullName` works correctly in the code below:
@@ -198,13 +203,16 @@ alert(admin.fullName); // John Smith (*)
// setter triggers!
admin.fullName = "Alice Cooper"; // (**)
+
+alert(admin.fullName); // Alice Cooper, state of admin modified
+alert(user.fullName); // John Smith, state of user protected
```
Here in the line `(*)` the property `admin.fullName` has a getter in the prototype `user`, so it is called. And in the line `(**)` the property has a setter in the prototype, so it is called.
## The value of "this"
-An interesting question may arise in the example above: what's the value of `this` inside `set fullName(value)`? Where the properties `this.name` and `this.surname` are written: into `user` or `admin`?
+An interesting question may arise in the example above: what's the value of `this` inside `set fullName(value)`? Where are the properties `this.name` and `this.surname` written: into `user` or `admin`?
The answer is simple: `this` is not affected by prototypes at all.
@@ -212,7 +220,7 @@ The answer is simple: `this` is not affected by prototypes at all.
So, the setter call `admin.fullName=` uses `admin` as `this`, not `user`.
-That is actually a super-important thing, because we may have a big object with many methods and inherit from it. Then inherited objects can run its methods, and they will modify the state of these objects, not the big one.
+That is actually a super-important thing, because we may have a big object with many methods, and have objects that inherit from it. And when the inheriting objects run the inherited methods, they will modify only their own states, not the state of the big object.
For instance, here `animal` represents a "method storage", and `rabbit` makes use of it.
@@ -245,16 +253,86 @@ alert(animal.isSleeping); // undefined (no such property in the prototype)
The resulting picture:
-
+
-If we had other objects like `bird`, `snake` etc inheriting from `animal`, they would also gain access to methods of `animal`. But `this` in each method would be the corresponding object, evaluated at the call-time (before dot), not `animal`. So when we write data into `this`, it is stored into these objects.
+If we had other objects, like `bird`, `snake`, etc., inheriting from `animal`, they would also gain access to methods of `animal`. But `this` in each method call would be the corresponding object, evaluated at the call-time (before dot), not `animal`. So when we write data into `this`, it is stored into these objects.
As a result, methods are shared, but the object state is not.
+## for..in loop
+
+The `for..in` loop iterates over inherited properties too.
+
+For instance:
+
+```js run
+let animal = {
+ eats: true
+};
+
+let rabbit = {
+ jumps: true,
+ __proto__: animal
+};
+
+*!*
+// Object.keys only returns own keys
+alert(Object.keys(rabbit)); // jumps
+*/!*
+
+*!*
+// for..in loops over both own and inherited keys
+for(let prop in rabbit) alert(prop); // jumps, then eats
+*/!*
+```
+
+If that's not what we want, and we'd like to exclude inherited properties, there's a built-in method [obj.hasOwnProperty(key)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty): it returns `true` if `obj` has its own (not inherited) property named `key`.
+
+So we can filter out inherited properties (or do something else with them):
+
+```js run
+let animal = {
+ eats: true
+};
+
+let rabbit = {
+ jumps: true,
+ __proto__: animal
+};
+
+for(let prop in rabbit) {
+ let isOwn = rabbit.hasOwnProperty(prop);
+
+ if (isOwn) {
+ alert(`Our: ${prop}`); // Our: jumps
+ } else {
+ alert(`Inherited: ${prop}`); // Inherited: eats
+ }
+}
+```
+
+Here we have the following inheritance chain: `rabbit` inherits from `animal`, that inherits from `Object.prototype` (because `animal` is a literal object `{...}`, so it's by default), and then `null` above it:
+
+
+
+Note, there's one funny thing. Where is the method `rabbit.hasOwnProperty` coming from? We did not define it. Looking at the chain we can see that the method is provided by `Object.prototype.hasOwnProperty`. In other words, it's inherited.
+
+...But why does `hasOwnProperty` not appear in the `for..in` loop like `eats` and `jumps` do, if `for..in` lists inherited properties?
+
+The answer is simple: it's not enumerable. Just like all other properties of `Object.prototype`, it has `enumerable:false` flag. And `for..in` only lists enumerable properties. That's why it and the rest of the `Object.prototype` properties are not listed.
+
+```smart header="Almost all other key/value-getting methods ignore inherited properties"
+Almost all other key/value-getting methods, such as `Object.keys`, `Object.values` and so on ignore inherited properties.
+
+They only operate on the object itself. Properties from the prototype are *not* taken into account.
+```
+
## Summary
- In JavaScript, all objects have a hidden `[[Prototype]]` property that's either another object or `null`.
- We can use `obj.__proto__` to access it (a historical getter/setter, there are other ways, to be covered soon).
- The object referenced by `[[Prototype]]` is called a "prototype".
-- If we want to read a property of `obj` or call a method, and it doesn't exist, then JavaScript tries to find it in the prototype. Write/delete operations work directly on the object, they don't use the prototype (unless the property is actually a setter).
+- If we want to read a property of `obj` or call a method, and it doesn't exist, then JavaScript tries to find it in the prototype.
+- Write/delete operations act directly on the object, they don't use the prototype (assuming it's a data property, not a setter).
- If we call `obj.method()`, and the `method` is taken from the prototype, `this` still references `obj`. So methods always work with the current object even if they are inherited.
+- The `for..in` loop iterates over both its own and its inherited properties. All other key/value-getting methods only operate on the object itself.
diff --git a/1-js/08-prototypes/01-prototype-inheritance/object-prototype-empty.png b/1-js/08-prototypes/01-prototype-inheritance/object-prototype-empty.png
deleted file mode 100644
index d0a905b3ad..0000000000
Binary files a/1-js/08-prototypes/01-prototype-inheritance/object-prototype-empty.png and /dev/null differ
diff --git a/1-js/08-prototypes/01-prototype-inheritance/object-prototype-empty.svg b/1-js/08-prototypes/01-prototype-inheritance/object-prototype-empty.svg
new file mode 100644
index 0000000000..eb79c19ffd
--- /dev/null
+++ b/1-js/08-prototypes/01-prototype-inheritance/object-prototype-empty.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/08-prototypes/01-prototype-inheritance/object-prototype-empty@2x.png b/1-js/08-prototypes/01-prototype-inheritance/object-prototype-empty@2x.png
deleted file mode 100644
index 91a2d084f2..0000000000
Binary files a/1-js/08-prototypes/01-prototype-inheritance/object-prototype-empty@2x.png and /dev/null differ
diff --git a/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-chain.png b/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-chain.png
deleted file mode 100644
index 2b07f76d63..0000000000
Binary files a/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-chain.png and /dev/null differ
diff --git a/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-chain.svg b/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-chain.svg
new file mode 100644
index 0000000000..4bf580ae77
--- /dev/null
+++ b/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-chain.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-chain@2x.png b/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-chain@2x.png
deleted file mode 100644
index b3976f964b..0000000000
Binary files a/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-chain@2x.png and /dev/null differ
diff --git a/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-walk-2.png b/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-walk-2.png
deleted file mode 100644
index 3c122d5fa4..0000000000
Binary files a/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-walk-2.png and /dev/null differ
diff --git a/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-walk-2.svg b/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-walk-2.svg
new file mode 100644
index 0000000000..838c78395b
--- /dev/null
+++ b/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-walk-2.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-walk-2@2x.png b/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-walk-2@2x.png
deleted file mode 100644
index 35db68f163..0000000000
Binary files a/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-walk-2@2x.png and /dev/null differ
diff --git a/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-walk-3.png b/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-walk-3.png
deleted file mode 100644
index 33e71d8ff9..0000000000
Binary files a/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-walk-3.png and /dev/null differ
diff --git a/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-walk-3.svg b/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-walk-3.svg
new file mode 100644
index 0000000000..d791e5390d
--- /dev/null
+++ b/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-walk-3.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-walk-3@2x.png b/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-walk-3@2x.png
deleted file mode 100644
index 29d6883c1e..0000000000
Binary files a/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-walk-3@2x.png and /dev/null differ
diff --git a/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-walk.png b/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-walk.png
deleted file mode 100644
index 3b26a582c4..0000000000
Binary files a/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-walk.png and /dev/null differ
diff --git a/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-walk.svg b/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-walk.svg
new file mode 100644
index 0000000000..b324710286
--- /dev/null
+++ b/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-walk.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-walk@2x.png b/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-walk@2x.png
deleted file mode 100644
index 66aaa5018c..0000000000
Binary files a/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit-walk@2x.png and /dev/null differ
diff --git a/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit.png b/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit.png
deleted file mode 100644
index eae25e0d19..0000000000
Binary files a/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit.png and /dev/null differ
diff --git a/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit.svg b/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit.svg
new file mode 100644
index 0000000000..4f3c1bc0ec
--- /dev/null
+++ b/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit@2x.png b/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit@2x.png
deleted file mode 100644
index 391945719e..0000000000
Binary files a/1-js/08-prototypes/01-prototype-inheritance/proto-animal-rabbit@2x.png and /dev/null differ
diff --git a/1-js/08-prototypes/01-prototype-inheritance/proto-user-admin.png b/1-js/08-prototypes/01-prototype-inheritance/proto-user-admin.png
deleted file mode 100644
index dae56a325a..0000000000
Binary files a/1-js/08-prototypes/01-prototype-inheritance/proto-user-admin.png and /dev/null differ
diff --git a/1-js/08-prototypes/01-prototype-inheritance/proto-user-admin.svg b/1-js/08-prototypes/01-prototype-inheritance/proto-user-admin.svg
new file mode 100644
index 0000000000..bf0baf013a
--- /dev/null
+++ b/1-js/08-prototypes/01-prototype-inheritance/proto-user-admin.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/08-prototypes/01-prototype-inheritance/proto-user-admin@2x.png b/1-js/08-prototypes/01-prototype-inheritance/proto-user-admin@2x.png
deleted file mode 100644
index 6443eee6ae..0000000000
Binary files a/1-js/08-prototypes/01-prototype-inheritance/proto-user-admin@2x.png and /dev/null differ
diff --git a/1-js/08-prototypes/01-prototype-inheritance/rabbit-animal-object.svg b/1-js/08-prototypes/01-prototype-inheritance/rabbit-animal-object.svg
new file mode 100644
index 0000000000..32a9858f83
--- /dev/null
+++ b/1-js/08-prototypes/01-prototype-inheritance/rabbit-animal-object.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/08-prototypes/02-function-prototype/1-changing-prototype/solution.md b/1-js/08-prototypes/02-function-prototype/1-changing-prototype/solution.md
index 771e3061c9..ebbdf3a7c1 100644
--- a/1-js/08-prototypes/02-function-prototype/1-changing-prototype/solution.md
+++ b/1-js/08-prototypes/02-function-prototype/1-changing-prototype/solution.md
@@ -7,7 +7,7 @@ Answers:
2. `false`.
- Objects are assigned by reference. The object from `Rabbit.prototype` is not duplicated, it's still a single object is referenced both by `Rabbit.prototype` and by the `[[Prototype]]` of `rabbit`.
+ Objects are assigned by reference. The object from `Rabbit.prototype` is not duplicated, it's still a single object referenced both by `Rabbit.prototype` and by the `[[Prototype]]` of `rabbit`.
So when we change its content through one reference, it is visible through the other one.
diff --git a/1-js/08-prototypes/02-function-prototype/1-changing-prototype/task.md b/1-js/08-prototypes/02-function-prototype/1-changing-prototype/task.md
index 4b8522d3dd..2838c125ad 100644
--- a/1-js/08-prototypes/02-function-prototype/1-changing-prototype/task.md
+++ b/1-js/08-prototypes/02-function-prototype/1-changing-prototype/task.md
@@ -20,7 +20,7 @@ alert( rabbit.eats ); // true
```
-1. We added one more string (emphasized), what `alert` shows now?
+1. We added one more string (emphasized). What will `alert` show now?
```js
function Rabbit() {}
@@ -54,7 +54,7 @@ alert( rabbit.eats ); // true
alert( rabbit.eats ); // ?
```
-3. Like this (replaced one line)?
+3. And like this (replaced one line)?
```js
function Rabbit() {}
diff --git a/1-js/08-prototypes/02-function-prototype/4-new-object-same-constructor/solution.md b/1-js/08-prototypes/02-function-prototype/4-new-object-same-constructor/solution.md
index 43190e163b..372d50dd6d 100644
--- a/1-js/08-prototypes/02-function-prototype/4-new-object-same-constructor/solution.md
+++ b/1-js/08-prototypes/02-function-prototype/4-new-object-same-constructor/solution.md
@@ -15,7 +15,7 @@ alert( user2.name ); // Pete (worked!)
It worked, because `User.prototype.constructor == User`.
-..But if someone, so to say, overwrites `User.prototype` and forgets to recreate `"constructor"`, then it would fail.
+..But if someone, so to speak, overwrites `User.prototype` and forgets to recreate `constructor` to reference `User`, then it would fail.
For instance:
@@ -38,7 +38,12 @@ Why `user2.name` is `undefined`?
Here's how `new user.constructor('Pete')` works:
1. First, it looks for `constructor` in `user`. Nothing.
-2. Then it follows the prototype chain. The prototype of `user` is `User.prototype`, and it also has nothing.
-3. The value of `User.prototype` is a plain object `{}`, its prototype is `Object.prototype`. And there is `Object.prototype.constructor == Object`. So it is used.
+2. Then it follows the prototype chain. The prototype of `user` is `User.prototype`, and it also has no `constructor` (because we "forgot" to set it right!).
+3. Going further up the chain, `User.prototype` is a plain object, its prototype is the built-in `Object.prototype`.
+4. Finally, for the built-in `Object.prototype`, there's a built-in `Object.prototype.constructor == Object`. So it is used.
-At the end, we have `let user2 = new Object('Pete')`. The built-in `Object` constructor ignores arguments, it always creates an empty object -- that's what we have in `user2` after all.
+Finally, at the end, we have `let user2 = new Object('Pete')`.
+
+Probably, that's not what we want. We'd like to create `new User`, not `new Object`. That's the outcome of the missing `constructor`.
+
+(Just in case you're curious, the `new Object(...)` call converts its argument to an object. That's a theoretical thing, in practice no one calls `new Object` with a value, and generally we don't use `new Object` to make objects at all).
\ No newline at end of file
diff --git a/1-js/08-prototypes/02-function-prototype/article.md b/1-js/08-prototypes/02-function-prototype/article.md
index 6de6e03efd..b1ef518266 100644
--- a/1-js/08-prototypes/02-function-prototype/article.md
+++ b/1-js/08-prototypes/02-function-prototype/article.md
@@ -2,7 +2,7 @@
Remember, new objects can be created with a constructor function, like `new F()`.
-If `F.prototype` is an object, then `new` operator uses it to set `[[Prototype]]` for the new object.
+If `F.prototype` is an object, then the `new` operator uses it to set `[[Prototype]]` for the new object.
```smart
JavaScript had prototypal inheritance from the beginning. It was one of the core features of the language.
@@ -36,14 +36,14 @@ Setting `Rabbit.prototype = animal` literally states the following: "When a `new
That's the resulting picture:
-
+
On the picture, `"prototype"` is a horizontal arrow, meaning a regular property, and `[[Prototype]]` is vertical, meaning the inheritance of `rabbit` from `animal`.
```smart header="`F.prototype` only used at `new F` time"
-`F.prototype` is only used when `new F` is called, it assigns `[[Prototype]]` of the new object. After that, there's no connection between `F.prototype` and the new object. Think of it as a "one-time gift".
+`F.prototype` property is only used when `new F` is called, it assigns `[[Prototype]]` of the new object.
-After the creation, `F.prototype` may change, new objects created by `new F` will have another `[[Prototype]]`, but already existing objects keep the old one.
+If, after the creation, `F.prototype` property changes (`F.prototype = `), then new objects created by `new F` will have another object as `[[Prototype]]`, but already existing objects keep the old one.
```
## Default F.prototype, constructor property
@@ -62,7 +62,7 @@ Rabbit.prototype = { constructor: Rabbit };
*/
```
-
+
We can check it:
@@ -86,7 +86,7 @@ let rabbit = new Rabbit(); // inherits from {constructor: Rabbit}
alert(rabbit.constructor == Rabbit); // true (from prototype)
```
-
+
We can use `constructor` property to create a new object using the same constructor as the existing one.
@@ -158,11 +158,11 @@ Rabbit.prototype = {
In this chapter we briefly described the way of setting a `[[Prototype]]` for objects created via a constructor function. Later we'll see more advanced programming patterns that rely on it.
-Everything is quite simple, just few notes to make things clear:
+Everything is quite simple, just a few notes to make things clear:
-- The `F.prototype` property is not the same as `[[Prototype]]`. The only thing `F.prototype` does: it sets `[[Prototype]]` of new objects when `new F()` is called.
-- The value of `F.prototype` should be either an object or null: other values won't work.
-- The `"prototype"` property only has such a special effect when is set to a constructor function, and invoked with `new`.
+- The `F.prototype` property (don't mistake it for `[[Prototype]]`) sets `[[Prototype]]` of new objects when `new F()` is called.
+- The value of `F.prototype` should be either an object or `null`: other values won't work.
+- The `"prototype"` property only has such a special effect when set on a constructor function, and invoked with `new`.
On regular objects the `prototype` is nothing special:
```js
diff --git a/1-js/08-prototypes/02-function-prototype/function-prototype-constructor.png b/1-js/08-prototypes/02-function-prototype/function-prototype-constructor.png
deleted file mode 100644
index 92f80cea7c..0000000000
Binary files a/1-js/08-prototypes/02-function-prototype/function-prototype-constructor.png and /dev/null differ
diff --git a/1-js/08-prototypes/02-function-prototype/function-prototype-constructor.svg b/1-js/08-prototypes/02-function-prototype/function-prototype-constructor.svg
new file mode 100644
index 0000000000..59d60b397a
--- /dev/null
+++ b/1-js/08-prototypes/02-function-prototype/function-prototype-constructor.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/08-prototypes/02-function-prototype/function-prototype-constructor@2x.png b/1-js/08-prototypes/02-function-prototype/function-prototype-constructor@2x.png
deleted file mode 100644
index d8c83f6ed4..0000000000
Binary files a/1-js/08-prototypes/02-function-prototype/function-prototype-constructor@2x.png and /dev/null differ
diff --git a/1-js/08-prototypes/02-function-prototype/native-prototypes-array-tostring.png b/1-js/08-prototypes/02-function-prototype/native-prototypes-array-tostring.png
deleted file mode 100644
index 02f0e747d5..0000000000
Binary files a/1-js/08-prototypes/02-function-prototype/native-prototypes-array-tostring.png and /dev/null differ
diff --git a/1-js/08-prototypes/02-function-prototype/native-prototypes-array-tostring@2x.png b/1-js/08-prototypes/02-function-prototype/native-prototypes-array-tostring@2x.png
deleted file mode 100644
index 7abe2c93e3..0000000000
Binary files a/1-js/08-prototypes/02-function-prototype/native-prototypes-array-tostring@2x.png and /dev/null differ
diff --git a/1-js/08-prototypes/02-function-prototype/native-prototypes-classes.png b/1-js/08-prototypes/02-function-prototype/native-prototypes-classes.png
deleted file mode 100644
index 03737f2da7..0000000000
Binary files a/1-js/08-prototypes/02-function-prototype/native-prototypes-classes.png and /dev/null differ
diff --git a/1-js/08-prototypes/02-function-prototype/native-prototypes-classes@2x.png b/1-js/08-prototypes/02-function-prototype/native-prototypes-classes@2x.png
deleted file mode 100644
index a2e9390e4f..0000000000
Binary files a/1-js/08-prototypes/02-function-prototype/native-prototypes-classes@2x.png and /dev/null differ
diff --git a/1-js/08-prototypes/02-function-prototype/object-prototype-1.png b/1-js/08-prototypes/02-function-prototype/object-prototype-1.png
deleted file mode 100644
index b0ff15324a..0000000000
Binary files a/1-js/08-prototypes/02-function-prototype/object-prototype-1.png and /dev/null differ
diff --git a/1-js/08-prototypes/02-function-prototype/object-prototype-1@2x.png b/1-js/08-prototypes/02-function-prototype/object-prototype-1@2x.png
deleted file mode 100644
index 5d4365cf57..0000000000
Binary files a/1-js/08-prototypes/02-function-prototype/object-prototype-1@2x.png and /dev/null differ
diff --git a/1-js/08-prototypes/02-function-prototype/object-prototype.png b/1-js/08-prototypes/02-function-prototype/object-prototype.png
deleted file mode 100644
index 581105aa71..0000000000
Binary files a/1-js/08-prototypes/02-function-prototype/object-prototype.png and /dev/null differ
diff --git a/1-js/08-prototypes/02-function-prototype/object-prototype@2x.png b/1-js/08-prototypes/02-function-prototype/object-prototype@2x.png
deleted file mode 100644
index 4f0e53302b..0000000000
Binary files a/1-js/08-prototypes/02-function-prototype/object-prototype@2x.png and /dev/null differ
diff --git a/1-js/08-prototypes/02-function-prototype/proto-constructor-animal-rabbit.png b/1-js/08-prototypes/02-function-prototype/proto-constructor-animal-rabbit.png
deleted file mode 100644
index 2a745e8fe2..0000000000
Binary files a/1-js/08-prototypes/02-function-prototype/proto-constructor-animal-rabbit.png and /dev/null differ
diff --git a/1-js/08-prototypes/02-function-prototype/proto-constructor-animal-rabbit.svg b/1-js/08-prototypes/02-function-prototype/proto-constructor-animal-rabbit.svg
new file mode 100644
index 0000000000..ede4e1227e
--- /dev/null
+++ b/1-js/08-prototypes/02-function-prototype/proto-constructor-animal-rabbit.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/08-prototypes/02-function-prototype/proto-constructor-animal-rabbit@2x.png b/1-js/08-prototypes/02-function-prototype/proto-constructor-animal-rabbit@2x.png
deleted file mode 100644
index 609ac141aa..0000000000
Binary files a/1-js/08-prototypes/02-function-prototype/proto-constructor-animal-rabbit@2x.png and /dev/null differ
diff --git a/1-js/08-prototypes/02-function-prototype/rabbit-animal-object.png b/1-js/08-prototypes/02-function-prototype/rabbit-animal-object.png
deleted file mode 100644
index e1758e9f1e..0000000000
Binary files a/1-js/08-prototypes/02-function-prototype/rabbit-animal-object.png and /dev/null differ
diff --git a/1-js/08-prototypes/02-function-prototype/rabbit-animal-object@2x.png b/1-js/08-prototypes/02-function-prototype/rabbit-animal-object@2x.png
deleted file mode 100644
index 2d282a9d4c..0000000000
Binary files a/1-js/08-prototypes/02-function-prototype/rabbit-animal-object@2x.png and /dev/null differ
diff --git a/1-js/08-prototypes/02-function-prototype/rabbit-prototype-constructor.png b/1-js/08-prototypes/02-function-prototype/rabbit-prototype-constructor.png
deleted file mode 100644
index fe71481c28..0000000000
Binary files a/1-js/08-prototypes/02-function-prototype/rabbit-prototype-constructor.png and /dev/null differ
diff --git a/1-js/08-prototypes/02-function-prototype/rabbit-prototype-constructor.svg b/1-js/08-prototypes/02-function-prototype/rabbit-prototype-constructor.svg
new file mode 100644
index 0000000000..54b3d79804
--- /dev/null
+++ b/1-js/08-prototypes/02-function-prototype/rabbit-prototype-constructor.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/08-prototypes/02-function-prototype/rabbit-prototype-constructor@2x.png b/1-js/08-prototypes/02-function-prototype/rabbit-prototype-constructor@2x.png
deleted file mode 100644
index 09f7631fab..0000000000
Binary files a/1-js/08-prototypes/02-function-prototype/rabbit-prototype-constructor@2x.png and /dev/null differ
diff --git a/1-js/08-prototypes/03-native-prototypes/2-defer-to-prototype-extended/solution.md b/1-js/08-prototypes/03-native-prototypes/2-defer-to-prototype-extended/solution.md
index e3651683fa..99c358c9b0 100644
--- a/1-js/08-prototypes/03-native-prototypes/2-defer-to-prototype-extended/solution.md
+++ b/1-js/08-prototypes/03-native-prototypes/2-defer-to-prototype-extended/solution.md
@@ -15,3 +15,27 @@ function f(a, b) {
f.defer(1000)(1, 2); // shows 3 after 1 sec
```
+
+Please note: we use `this` in `f.apply` to make our decoration work for object methods.
+
+So if the wrapper function is called as an object method, then `this` is passed to the original method `f`.
+
+```js run
+Function.prototype.defer = function(ms) {
+ let f = this;
+ return function(...args) {
+ setTimeout(() => f.apply(this, args), ms);
+ }
+};
+
+let user = {
+ name: "John",
+ sayHi() {
+ alert(this.name);
+ }
+}
+
+user.sayHi = user.sayHi.defer(1000);
+
+user.sayHi();
+```
diff --git a/1-js/08-prototypes/03-native-prototypes/article.md b/1-js/08-prototypes/03-native-prototypes/article.md
index a3fdfc6c70..bdfc86dd8d 100644
--- a/1-js/08-prototypes/03-native-prototypes/article.md
+++ b/1-js/08-prototypes/03-native-prototypes/article.md
@@ -2,7 +2,7 @@
The `"prototype"` property is widely used by the core of JavaScript itself. All built-in constructor functions use it.
-We'll see how it is for plain objects first, and then for more complex ones.
+First we'll look at the details, and then how to use it for adding new capabilities to built-in objects.
## Object.prototype
@@ -15,17 +15,17 @@ alert( obj ); // "[object Object]" ?
Where's the code that generates the string `"[object Object]"`? That's a built-in `toString` method, but where is it? The `obj` is empty!
-...But the short notation `obj = {}` is the same as `obj = new Object()`, where `Object` -- is a built-in object constructor function. And that function has `Object.prototype` that references a huge object with `toString` and other functions.
+...But the short notation `obj = {}` is the same as `obj = new Object()`, where `Object` is a built-in object constructor function, with its own `prototype` referencing a huge object with `toString` and other methods.
-Like this (all that is built-in):
+Here's what's going on:
-
+
-When `new Object()` is called (or a literal object `{...}` is created), the `[[Prototype]]` of it is set to `Object.prototype` by the rule that we've discussed in the previous chapter:
+When `new Object()` is called (or a literal object `{...}` is created), the `[[Prototype]]` of it is set to `Object.prototype` according to the rule that we discussed in the previous chapter:
-
+
-Afterwards when `obj.toString()` is called -- the method is taken from `Object.prototype`.
+So then when `obj.toString()` is called the method is taken from `Object.prototype`.
We can check it like this:
@@ -33,10 +33,12 @@ We can check it like this:
let obj = {};
alert(obj.__proto__ === Object.prototype); // true
-// obj.toString === obj.__proto__.toString == Object.prototype.toString
+
+alert(obj.toString === obj.__proto__.toString); //true
+alert(obj.toString === Object.prototype.toString); //true
```
-Please note that there is no additional `[[Prototype]]` in the chain above `Object.prototype`:
+Please note that there is no more `[[Prototype]]` in the chain above `Object.prototype`:
```js run
alert(Object.prototype.__proto__); // null
@@ -46,13 +48,13 @@ alert(Object.prototype.__proto__); // null
Other built-in objects such as `Array`, `Date`, `Function` and others also keep methods in prototypes.
-For instance, when we create an array `[1, 2, 3]`, the default `new Array()` constructor is used internally. So the array data is written into the new object, and `Array.prototype` becomes its prototype and provides methods. That's very memory-efficient.
+For instance, when we create an array `[1, 2, 3]`, the default `new Array()` constructor is used internally. So `Array.prototype` becomes its prototype and provides methods. That's very memory-efficient.
-By specification, all built-in prototypes have `Object.prototype` on the top. Sometimes people say that "everything inherits from objects".
+By specification, all of the built-in prototypes have `Object.prototype` on the top. That's why some people say that "everything inherits from objects".
Here's the overall picture (for 3 built-ins to fit):
-
+
Let's check the prototypes manually:
@@ -79,14 +81,14 @@ alert(arr); // 1,2,3 <-- the result of Array.prototype.toString
As we've seen before, `Object.prototype` has `toString` as well, but `Array.prototype` is closer in the chain, so the array variant is used.
-
+
-In-browser tools like Chrome developer console also show inheritance (may need to use `console.dir` for built-in objects):
+In-browser tools like Chrome developer console also show inheritance (`console.dir` may need to be used for built-in objects):

-Other built-in objects also work the same way. Even functions. They are objects of a built-in `Function` constructor, and their methods: `call/apply` and others are taken from `Function.prototype`. Functions have their own `toString` too.
+Other built-in objects also work the same way. Even functions -- they are objects of a built-in `Function` constructor, and their methods (`call`/`apply` and others) are taken from `Function.prototype`. Functions have their own `toString` too.
```js run
function f() {}
@@ -99,12 +101,12 @@ alert(f.__proto__.__proto__ == Object.prototype); // true, inherit from objects
The most intricate thing happens with strings, numbers and booleans.
-As we remember, they are not objects. But if we try to access their properties, then temporary wrapper objects are created using built-in constructors `String`, `Number`, `Boolean`, they provide the methods and disappear.
+As we remember, they are not objects. But if we try to access their properties, temporary wrapper objects are created using built-in constructors `String`, `Number` and `Boolean`. They provide the methods and disappear.
These objects are created invisibly to us and most engines optimize them out, but the specification describes it exactly this way. Methods of these objects also reside in prototypes, available as `String.prototype`, `Number.prototype` and `Boolean.prototype`.
```warn header="Values `null` and `undefined` have no object wrappers"
-Special values `null` and `undefined` stand apart. They have no object wrappers, so methods and properties are not available for them. And there are no corresponding prototypes too.
+Special values `null` and `undefined` stand apart. They have no object wrappers, so methods and properties are not available for them. And there are no corresponding prototypes either.
```
## Changing native prototypes [#native-prototype-change]
@@ -119,19 +121,19 @@ String.prototype.show = function() {
"BOOM!".show(); // BOOM!
```
-During the process of development we may have ideas which new built-in methods we'd like to have. And there may be a slight temptation to add them to native prototypes. But that is generally a bad idea.
+During the process of development, we may have ideas for new built-in methods we'd like to have, and we may be tempted to add them to native prototypes. But that is generally a bad idea.
```warn
-Prototypes are global, so it's easy to get a conflict. If two libraries add a method `String.prototype.show`, then one of them overwrites the other one.
+Prototypes are global, so it's easy to get a conflict. If two libraries add a method `String.prototype.show`, then one of them will be overwriting the method of the other.
-So, generally modifying a native prototypeis considered a bad idea.
+So, generally, modifying a native prototype is considered a bad idea.
```
-**In modern programming, there is only one case when modifying native prototypes is approved. That's polyfilling.**
+**In modern programming, there is only one case where modifying native prototypes is approved. That's polyfilling.**
-Polyfilling is a term for making a substitute for a method that exists in JavaScript specification, but not yet supported by current JavaScript engine .
+Polyfilling is a term for making a substitute for a method that exists in the JavaScript specification, but is not yet supported by a particular JavaScript engine.
-Then we may implement it manually and populate the built-in prototype with it.
+We may then implement it manually and populate the built-in prototype with it.
For instance:
@@ -161,7 +163,7 @@ That's when we take a method from one object and copy it into another.
Some methods of native prototypes are often borrowed.
-For instance, if we're making an array-like object, we may want to copy some array methods to it.
+For instance, if we're making an array-like object, we may want to copy some `Array` methods to it.
E.g.
@@ -179,18 +181,18 @@ obj.join = Array.prototype.join;
alert( obj.join(',') ); // Hello,world!
```
-It works, because the internal algorithm of the built-in `join` method only cares about the correct indexes and the `length` property, it doesn't check that the object is indeed the array. And many built-in methods are like that.
+It works because the internal algorithm of the built-in `join` method only cares about the correct indexes and the `length` property. It doesn't check if the object is indeed an array. Many built-in methods are like that.
-Another possibility is to inherit by setting `obj.__proto__` to `Array.prototype`, then all `Array` methods are automatically available in `obj`.
+Another possibility is to inherit by setting `obj.__proto__` to `Array.prototype`, so all `Array` methods are automatically available in `obj`.
But that's impossible if `obj` already inherits from another object. Remember, we only can inherit from one object at a time.
-Borrowing methods is flexible, it allows to mix functionality from different objects if needed.
+Borrowing methods is flexible, it allows to mix functionalities from different objects if needed.
## Summary
- All built-in objects follow the same pattern:
- - The methods are stored in the prototype (`Array.prototype`, `Object.prototype`, `Date.prototype` etc).
- - The object itself stores only the data (array items, object properties, the date).
-- Primitives also store methods in prototypes of wrapper objects: `Number.prototype`, `String.prototype`, `Boolean.prototype`. There are no wrapper objects only for `undefined` and `null`.
-- Built-in prototypes can be modified or populated with new methods. But it's not recommended to change them. Probably the only allowable cause is when we add-in a new standard, but not yet supported by the engine JavaScript method.
+ - The methods are stored in the prototype (`Array.prototype`, `Object.prototype`, `Date.prototype`, etc.)
+ - The object itself stores only the data (array items, object properties, the date)
+- Primitives also store methods in prototypes of wrapper objects: `Number.prototype`, `String.prototype` and `Boolean.prototype`. Only `undefined` and `null` do not have wrapper objects
+- Built-in prototypes can be modified or populated with new methods. But it's not recommended to change them. The only allowable case is probably when we add-in a new standard, but it's not yet supported by the JavaScript engine
diff --git a/1-js/08-prototypes/03-native-prototypes/function-prototype-constructor.png b/1-js/08-prototypes/03-native-prototypes/function-prototype-constructor.png
deleted file mode 100644
index 92f80cea7c..0000000000
Binary files a/1-js/08-prototypes/03-native-prototypes/function-prototype-constructor.png and /dev/null differ
diff --git a/1-js/08-prototypes/03-native-prototypes/function-prototype-constructor.svg b/1-js/08-prototypes/03-native-prototypes/function-prototype-constructor.svg
new file mode 100644
index 0000000000..59d60b397a
--- /dev/null
+++ b/1-js/08-prototypes/03-native-prototypes/function-prototype-constructor.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/08-prototypes/03-native-prototypes/function-prototype-constructor@2x.png b/1-js/08-prototypes/03-native-prototypes/function-prototype-constructor@2x.png
deleted file mode 100644
index d8c83f6ed4..0000000000
Binary files a/1-js/08-prototypes/03-native-prototypes/function-prototype-constructor@2x.png and /dev/null differ
diff --git a/1-js/08-prototypes/03-native-prototypes/native-prototypes-array-tostring.png b/1-js/08-prototypes/03-native-prototypes/native-prototypes-array-tostring.png
deleted file mode 100644
index 02f0e747d5..0000000000
Binary files a/1-js/08-prototypes/03-native-prototypes/native-prototypes-array-tostring.png and /dev/null differ
diff --git a/1-js/08-prototypes/03-native-prototypes/native-prototypes-array-tostring.svg b/1-js/08-prototypes/03-native-prototypes/native-prototypes-array-tostring.svg
new file mode 100644
index 0000000000..ebb4f32051
--- /dev/null
+++ b/1-js/08-prototypes/03-native-prototypes/native-prototypes-array-tostring.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/08-prototypes/03-native-prototypes/native-prototypes-array-tostring@2x.png b/1-js/08-prototypes/03-native-prototypes/native-prototypes-array-tostring@2x.png
deleted file mode 100644
index 7abe2c93e3..0000000000
Binary files a/1-js/08-prototypes/03-native-prototypes/native-prototypes-array-tostring@2x.png and /dev/null differ
diff --git a/1-js/08-prototypes/03-native-prototypes/native-prototypes-classes.png b/1-js/08-prototypes/03-native-prototypes/native-prototypes-classes.png
deleted file mode 100644
index 03737f2da7..0000000000
Binary files a/1-js/08-prototypes/03-native-prototypes/native-prototypes-classes.png and /dev/null differ
diff --git a/1-js/08-prototypes/03-native-prototypes/native-prototypes-classes.svg b/1-js/08-prototypes/03-native-prototypes/native-prototypes-classes.svg
new file mode 100644
index 0000000000..4d6129e0a0
--- /dev/null
+++ b/1-js/08-prototypes/03-native-prototypes/native-prototypes-classes.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/08-prototypes/03-native-prototypes/native-prototypes-classes@2x.png b/1-js/08-prototypes/03-native-prototypes/native-prototypes-classes@2x.png
deleted file mode 100644
index a2e9390e4f..0000000000
Binary files a/1-js/08-prototypes/03-native-prototypes/native-prototypes-classes@2x.png and /dev/null differ
diff --git a/1-js/08-prototypes/03-native-prototypes/object-prototype-1.png b/1-js/08-prototypes/03-native-prototypes/object-prototype-1.png
deleted file mode 100644
index b0ff15324a..0000000000
Binary files a/1-js/08-prototypes/03-native-prototypes/object-prototype-1.png and /dev/null differ
diff --git a/1-js/08-prototypes/03-native-prototypes/object-prototype-1.svg b/1-js/08-prototypes/03-native-prototypes/object-prototype-1.svg
new file mode 100644
index 0000000000..9630e68e27
--- /dev/null
+++ b/1-js/08-prototypes/03-native-prototypes/object-prototype-1.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/08-prototypes/03-native-prototypes/object-prototype-1@2x.png b/1-js/08-prototypes/03-native-prototypes/object-prototype-1@2x.png
deleted file mode 100644
index 5d4365cf57..0000000000
Binary files a/1-js/08-prototypes/03-native-prototypes/object-prototype-1@2x.png and /dev/null differ
diff --git a/1-js/08-prototypes/03-native-prototypes/object-prototype-null.png b/1-js/08-prototypes/03-native-prototypes/object-prototype-null.png
deleted file mode 100644
index 9115d5f3ef..0000000000
Binary files a/1-js/08-prototypes/03-native-prototypes/object-prototype-null.png and /dev/null differ
diff --git a/1-js/08-prototypes/03-native-prototypes/object-prototype-null.svg b/1-js/08-prototypes/03-native-prototypes/object-prototype-null.svg
new file mode 100644
index 0000000000..9ccb342299
--- /dev/null
+++ b/1-js/08-prototypes/03-native-prototypes/object-prototype-null.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/08-prototypes/03-native-prototypes/object-prototype-null@2x.png b/1-js/08-prototypes/03-native-prototypes/object-prototype-null@2x.png
deleted file mode 100644
index 3120a8d561..0000000000
Binary files a/1-js/08-prototypes/03-native-prototypes/object-prototype-null@2x.png and /dev/null differ
diff --git a/1-js/08-prototypes/03-native-prototypes/object-prototype.png b/1-js/08-prototypes/03-native-prototypes/object-prototype.png
deleted file mode 100644
index 581105aa71..0000000000
Binary files a/1-js/08-prototypes/03-native-prototypes/object-prototype.png and /dev/null differ
diff --git a/1-js/08-prototypes/03-native-prototypes/object-prototype.svg b/1-js/08-prototypes/03-native-prototypes/object-prototype.svg
new file mode 100644
index 0000000000..024dd30213
--- /dev/null
+++ b/1-js/08-prototypes/03-native-prototypes/object-prototype.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/08-prototypes/03-native-prototypes/object-prototype@2x.png b/1-js/08-prototypes/03-native-prototypes/object-prototype@2x.png
deleted file mode 100644
index 4f0e53302b..0000000000
Binary files a/1-js/08-prototypes/03-native-prototypes/object-prototype@2x.png and /dev/null differ
diff --git a/1-js/08-prototypes/03-native-prototypes/proto-constructor-animal-rabbit.png b/1-js/08-prototypes/03-native-prototypes/proto-constructor-animal-rabbit.png
deleted file mode 100644
index 2a745e8fe2..0000000000
Binary files a/1-js/08-prototypes/03-native-prototypes/proto-constructor-animal-rabbit.png and /dev/null differ
diff --git a/1-js/08-prototypes/03-native-prototypes/proto-constructor-animal-rabbit@2x.png b/1-js/08-prototypes/03-native-prototypes/proto-constructor-animal-rabbit@2x.png
deleted file mode 100644
index 609ac141aa..0000000000
Binary files a/1-js/08-prototypes/03-native-prototypes/proto-constructor-animal-rabbit@2x.png and /dev/null differ
diff --git a/1-js/08-prototypes/03-native-prototypes/rabbit-prototype-constructor.png b/1-js/08-prototypes/03-native-prototypes/rabbit-prototype-constructor.png
deleted file mode 100644
index fe71481c28..0000000000
Binary files a/1-js/08-prototypes/03-native-prototypes/rabbit-prototype-constructor.png and /dev/null differ
diff --git a/1-js/08-prototypes/03-native-prototypes/rabbit-prototype-constructor.svg b/1-js/08-prototypes/03-native-prototypes/rabbit-prototype-constructor.svg
new file mode 100644
index 0000000000..54b3d79804
--- /dev/null
+++ b/1-js/08-prototypes/03-native-prototypes/rabbit-prototype-constructor.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/08-prototypes/03-native-prototypes/rabbit-prototype-constructor@2x.png b/1-js/08-prototypes/03-native-prototypes/rabbit-prototype-constructor@2x.png
deleted file mode 100644
index 09f7631fab..0000000000
Binary files a/1-js/08-prototypes/03-native-prototypes/rabbit-prototype-constructor@2x.png and /dev/null differ
diff --git a/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/solution.md b/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/solution.md
index a92e17900e..f3c9cf0e52 100644
--- a/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/solution.md
+++ b/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/solution.md
@@ -28,4 +28,4 @@ alert(dictionary); // "apple,__proto__"
When we create a property using a descriptor, its flags are `false` by default. So in the code above, `dictionary.toString` is non-enumerable.
-See the the chapter [](info:property-descriptors) for review.
+See the chapter [](info:property-descriptors) for review.
diff --git a/1-js/08-prototypes/04-prototype-methods/article.md b/1-js/08-prototypes/04-prototype-methods/article.md
index 3a925ab18c..9c5f1eb3dd 100644
--- a/1-js/08-prototypes/04-prototype-methods/article.md
+++ b/1-js/08-prototypes/04-prototype-methods/article.md
@@ -3,15 +3,18 @@
In the first chapter of this section, we mentioned that there are modern methods to setup a prototype.
-The `__proto__` is considered outdated and somewhat deprecated (in browser-only part of the Javascript standard).
+Setting or reading the prototype with `obj.__proto__` is considered outdated and somewhat deprecated (moved to the so-called "Annex B" of the JavaScript standard, meant for browsers only).
-The modern methods are:
+The modern methods to get/set a prototype are:
-- [Object.create(proto[, descriptors])](mdn:js/Object/create) -- creates an empty object with given `proto` as `[[Prototype]]` and optional property descriptors.
- [Object.getPrototypeOf(obj)](mdn:js/Object/getPrototypeOf) -- returns the `[[Prototype]]` of `obj`.
- [Object.setPrototypeOf(obj, proto)](mdn:js/Object/setPrototypeOf) -- sets the `[[Prototype]]` of `obj` to `proto`.
-These should be used instead of `__proto__`.
+The only usage of `__proto__`, that's not frowned upon, is as a property when creating a new object: `{ __proto__: ... }`.
+
+Although, there's a special method for this too:
+
+- [Object.create(proto[, descriptors])](mdn:js/Object/create) -- creates an empty object with given `proto` as `[[Prototype]]` and optional property descriptors.
For instance:
@@ -22,12 +25,13 @@ let animal = {
// create a new object with animal as a prototype
*!*
-let rabbit = Object.create(animal);
+let rabbit = Object.create(animal); // same as {__proto__: animal}
*/!*
alert(rabbit.eats); // true
+
*!*
-alert(Object.getPrototypeOf(rabbit) === animal); // get the prototype of rabbit
+alert(Object.getPrototypeOf(rabbit) === animal); // true
*/!*
*!*
@@ -35,7 +39,9 @@ Object.setPrototypeOf(rabbit, {}); // change the prototype of rabbit to {}
*/!*
```
-`Object.create` has an optional second argument: property descriptors. We can provide additional properties to the new object there, like this:
+The `Object.create` method is a bit more powerful, as it has an optional second argument: property descriptors.
+
+We can provide additional properties to the new object there, like this:
```js run
let animal = {
@@ -56,35 +62,42 @@ The descriptors are in the same format as described in the chapter ...get __proto__: functionset __proto__: functionObject.prototypeObjectobj[[Prototype]]prototype
\ No newline at end of file
diff --git a/1-js/08-prototypes/04-prototype-methods/object-prototype-2@2x.png b/1-js/08-prototypes/04-prototype-methods/object-prototype-2@2x.png
deleted file mode 100644
index e42d39479e..0000000000
Binary files a/1-js/08-prototypes/04-prototype-methods/object-prototype-2@2x.png and /dev/null differ
diff --git a/1-js/08-prototypes/04-prototype-methods/object-prototype-null.png b/1-js/08-prototypes/04-prototype-methods/object-prototype-null.png
deleted file mode 100644
index 9115d5f3ef..0000000000
Binary files a/1-js/08-prototypes/04-prototype-methods/object-prototype-null.png and /dev/null differ
diff --git a/1-js/08-prototypes/04-prototype-methods/object-prototype-null.svg b/1-js/08-prototypes/04-prototype-methods/object-prototype-null.svg
new file mode 100644
index 0000000000..9ccb342299
--- /dev/null
+++ b/1-js/08-prototypes/04-prototype-methods/object-prototype-null.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/08-prototypes/04-prototype-methods/object-prototype-null@2x.png b/1-js/08-prototypes/04-prototype-methods/object-prototype-null@2x.png
deleted file mode 100644
index 3120a8d561..0000000000
Binary files a/1-js/08-prototypes/04-prototype-methods/object-prototype-null@2x.png and /dev/null differ
diff --git a/1-js/08-prototypes/05-getting-all-properties/article.md b/1-js/08-prototypes/05-getting-all-properties/article.md
deleted file mode 100644
index 3339066da6..0000000000
--- a/1-js/08-prototypes/05-getting-all-properties/article.md
+++ /dev/null
@@ -1,83 +0,0 @@
-
-# Getting all properties
-
-There are many ways to get keys/values from an object.
-
-Most of them operate on the object itself, excluding the prototype, let's recall them:
-
-- [Object.keys(obj)](mdn:js/Object/keys) / [Object.values(obj)](mdn:js/Object/values) / [Object.entries(obj)](mdn:js/Object/entries) -- returns an array of enumerable own string property names/values/key-value pairs. These methods only list *enumerable* properties, and those that have *strings as keys*.
-
-If we want symbolic properties:
-
-- [Object.getOwnPropertySymbols(obj)](mdn:js/Object/getOwnPropertySymbols) -- returns an array of all own symbolic property names.
-
-If we want non-enumerable properties:
-
-- [Object.getOwnPropertyNames(obj)](mdn:js/Object/getOwnPropertyNames) -- returns an array of all own string property names.
-
-If we want *all* properties:
-
-- [Reflect.ownKeys(obj)](mdn:js/Reflect/ownKeys) -- returns an array of all own property names.
-
-These methods are a bit different about which properties they return, but all of them operate on the object itself. Properties from the prototype are not listed.
-
-## for..in loop
-
-The `for..in` loop is different: it loops over inherited properties too.
-
-For instance:
-
-```js run
-let animal = {
- eats: true
-};
-
-let rabbit = {
- jumps: true,
- __proto__: animal
-};
-
-*!*
-// only own keys
-alert(Object.keys(rabbit)); // jumps
-*/!*
-
-*!*
-// inherited keys too
-for(let prop in rabbit) alert(prop); // jumps, then eats
-*/!*
-```
-
-If that's no what we want, and we'd like to exclude inherited properties, there's a built-in method [obj.hasOwnProperty(key)](mdn:js/Object/hasOwnProperty): it returns `true` if `obj` has its own (not inherited) property named `key`.
-
-So we can filter out inherited properties (or do something else with them):
-
-```js run
-let animal = {
- eats: true
-};
-
-let rabbit = {
- jumps: true,
- __proto__: animal
-};
-
-for(let prop in rabbit) {
- let isOwn = rabbit.hasOwnProperty(prop);
- alert(`${prop}: ${isOwn}`); // jumps: true, then eats: false
-}
-```
-
-Here we have the following inheritance chain: `rabbit`, then `animal`, then `Object.prototype` (because `animal` is a literal object `{...}`, so it's by default), and then `null` above it:
-
-
-
-Note, there's one funny thing. Where is the method `rabbit.hasOwnProperty` coming from? Looking at the chain we can see that the method is provided by `Object.prototype.hasOwnProperty`. In other words, it's inherited.
-
-...But why `hasOwnProperty` does not appear in `for..in` loop, if it lists all inherited properties? The answer is simple: it's not enumerable. Just like all other properties of `Object.prototype`. That's why they are not listed.
-
-## Summary
-
-Most methods ignore inherited properties, with a notable exception of `for..in`.
-
-For the latter we can use [obj.hasOwnProperty(key)](mdn:js/Object/hasOwnProperty): it returns `true` if `obj` has its own (not inherited) property named `key`.
diff --git a/1-js/08-prototypes/05-getting-all-properties/rabbit-animal-object.png b/1-js/08-prototypes/05-getting-all-properties/rabbit-animal-object.png
deleted file mode 100644
index e1758e9f1e..0000000000
Binary files a/1-js/08-prototypes/05-getting-all-properties/rabbit-animal-object.png and /dev/null differ
diff --git a/1-js/08-prototypes/05-getting-all-properties/rabbit-animal-object@2x.png b/1-js/08-prototypes/05-getting-all-properties/rabbit-animal-object@2x.png
deleted file mode 100644
index 2d282a9d4c..0000000000
Binary files a/1-js/08-prototypes/05-getting-all-properties/rabbit-animal-object@2x.png and /dev/null differ
diff --git a/1-js/09-classes/01-class-patterns/1-inheritance-error-assign/solution.md b/1-js/09-classes/01-class-patterns/1-inheritance-error-assign/solution.md
deleted file mode 100644
index 55f945ca5d..0000000000
--- a/1-js/09-classes/01-class-patterns/1-inheritance-error-assign/solution.md
+++ /dev/null
@@ -1,46 +0,0 @@
-Here's the line with the error:
-
-```js
-Rabbit.prototype = Animal.prototype;
-```
-
-Here `Rabbit.prototype` and `Animal.prototype` become the same object. So methods of both classes become mixed in that object.
-
-As a result, `Rabbit.prototype.walk` overwrites `Animal.prototype.walk`, so all animals start to bounce:
-
-```js run
-function Animal(name) {
- this.name = name;
-}
-
-Animal.prototype.walk = function() {
- alert(this.name + ' walks');
-};
-
-function Rabbit(name) {
- this.name = name;
-}
-
-*!*
-Rabbit.prototype = Animal.prototype;
-*/!*
-
-Rabbit.prototype.walk = function() {
- alert(this.name + " bounces!");
-};
-
-*!*
-let animal = new Animal("pig");
-animal.walk(); // pig bounces!
-*/!*
-```
-
-The correct variant would be:
-
-```js
-Rabbit.prototype.__proto__ = Animal.prototype;
-// or like this:
-Rabbit.prototype = Object.create(Animal.prototype);
-```
-
-That makes prototypes separate, each of them stores methods of the corresponding class, but `Rabbit.prototype` inherits from `Animal.prototype`.
diff --git a/1-js/09-classes/01-class-patterns/1-inheritance-error-assign/task.md b/1-js/09-classes/01-class-patterns/1-inheritance-error-assign/task.md
deleted file mode 100644
index ee486c3d67..0000000000
--- a/1-js/09-classes/01-class-patterns/1-inheritance-error-assign/task.md
+++ /dev/null
@@ -1,29 +0,0 @@
-importance: 5
-
----
-
-# An error in the inheritance
-
-Find an error in the prototypal inheritance below.
-
-What's wrong? What are consequences going to be?
-
-```js
-function Animal(name) {
- this.name = name;
-}
-
-Animal.prototype.walk = function() {
- alert(this.name + ' walks');
-};
-
-function Rabbit(name) {
- this.name = name;
-}
-
-Rabbit.prototype = Animal.prototype;
-
-Rabbit.prototype.walk = function() {
- alert(this.name + " bounces!");
-};
-```
diff --git a/1-js/09-classes/01-class-patterns/2-rewrite-to-prototypes/solution.md b/1-js/09-classes/01-class-patterns/2-rewrite-to-prototypes/solution.md
deleted file mode 100644
index 300b25d94c..0000000000
--- a/1-js/09-classes/01-class-patterns/2-rewrite-to-prototypes/solution.md
+++ /dev/null
@@ -1 +0,0 @@
-Please note that properties that were internal in functional style (`template`, `timer`) and the internal method `render` are marked private with the underscore `_`.
diff --git a/1-js/09-classes/01-class-patterns/2-rewrite-to-prototypes/solution.view/clock.js b/1-js/09-classes/01-class-patterns/2-rewrite-to-prototypes/solution.view/clock.js
deleted file mode 100644
index bdf7bb72dd..0000000000
--- a/1-js/09-classes/01-class-patterns/2-rewrite-to-prototypes/solution.view/clock.js
+++ /dev/null
@@ -1,32 +0,0 @@
-function Clock({ template }) {
- this.template = template;
-}
-
-Clock.prototype.render = function() {
- let date = new Date();
-
- let hours = date.getHours();
- if (hours < 10) hours = '0' + hours;
-
- let mins = date.getMinutes();
- if (mins < 10) mins = '0' + mins;
-
- let secs = date.getSeconds();
- if (secs < 10) secs = '0' + secs;
-
- let output = this.template
- .replace('h', hours)
- .replace('m', mins)
- .replace('s', secs);
-
- console.log(output);
-};
-
-Clock.prototype.stop = function() {
- clearInterval(this.timer);
-};
-
-Clock.prototype.start = function() {
- this.render();
- this.timer = setInterval(() => this.render(), 1000);
-};
diff --git a/1-js/09-classes/01-class-patterns/2-rewrite-to-prototypes/solution.view/index.html b/1-js/09-classes/01-class-patterns/2-rewrite-to-prototypes/solution.view/index.html
deleted file mode 100644
index fdee13d01b..0000000000
--- a/1-js/09-classes/01-class-patterns/2-rewrite-to-prototypes/solution.view/index.html
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
- Console clock
-
-
-
-
-
-
-
-
-
-
diff --git a/1-js/09-classes/01-class-patterns/2-rewrite-to-prototypes/source.view/clock.js b/1-js/09-classes/01-class-patterns/2-rewrite-to-prototypes/source.view/clock.js
deleted file mode 100644
index c4bfaa0ff8..0000000000
--- a/1-js/09-classes/01-class-patterns/2-rewrite-to-prototypes/source.view/clock.js
+++ /dev/null
@@ -1,34 +0,0 @@
-function Clock({ template }) {
-
- let timer;
-
- function render() {
- let date = new Date();
-
- let hours = date.getHours();
- if (hours < 10) hours = '0' + hours;
-
- let mins = date.getMinutes();
- if (mins < 10) mins = '0' + mins;
-
- let secs = date.getSeconds();
- if (secs < 10) secs = '0' + secs;
-
- let output = template
- .replace('h', hours)
- .replace('m', mins)
- .replace('s', secs);
-
- console.log(output);
- }
-
- this.stop = function() {
- clearInterval(timer);
- };
-
- this.start = function() {
- render();
- timer = setInterval(render, 1000);
- };
-
-}
diff --git a/1-js/09-classes/01-class-patterns/2-rewrite-to-prototypes/source.view/index.html b/1-js/09-classes/01-class-patterns/2-rewrite-to-prototypes/source.view/index.html
deleted file mode 100644
index fdee13d01b..0000000000
--- a/1-js/09-classes/01-class-patterns/2-rewrite-to-prototypes/source.view/index.html
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
- Console clock
-
-
-
-
-
-
-
-
-
-
diff --git a/1-js/09-classes/01-class-patterns/2-rewrite-to-prototypes/task.md b/1-js/09-classes/01-class-patterns/2-rewrite-to-prototypes/task.md
deleted file mode 100644
index 71131816be..0000000000
--- a/1-js/09-classes/01-class-patterns/2-rewrite-to-prototypes/task.md
+++ /dev/null
@@ -1,9 +0,0 @@
-importance: 5
-
----
-
-# Rewrite to prototypes
-
-The `Clock` class is written in functional style. Rewrite it using prototypes.
-
-P.S. The clock ticks in the console, open it to see.
diff --git a/1-js/09-classes/01-class-patterns/article.md b/1-js/09-classes/01-class-patterns/article.md
deleted file mode 100644
index 837941cb9e..0000000000
--- a/1-js/09-classes/01-class-patterns/article.md
+++ /dev/null
@@ -1,240 +0,0 @@
-
-# Class patterns
-
-```quote author="Wikipedia"
-In object-oriented programming, a *class* is an extensible program-code-template for creating objects, providing initial values for state (member variables) and implementations of behavior (member functions or methods).
-```
-
-There's a special syntax construct and a keyword `class` in JavaScript. But before studying it, we should consider that the term "class" comes from the theory of object-oriented programming. The definition is cited above, and it's language-independent.
-
-In JavaScript there are several well-known programming patterns to make classes even without using the `class` keyword. People talk about "classes" meaning no only those defined with `class`, but also with these patterns.
-
-The `class` construct will be described in the next chapter, but in JavaScript it's a "syntax sugar" and an extension of the prototypal class pattern described here.
-
-
-## Functional class pattern
-
-The constructor function below can be considered a "class" according to the definition:
-
-```js run
-function User(name) {
- this.sayHi = function() {
- alert(name);
- };
-}
-
-let user = new User("John");
-user.sayHi(); // John
-```
-
-It follows all parts of the definition:
-
-1. It is a "program-code-template" for creating objects (callable with `new`).
-2. It provides initial values for the state (`name` from parameters).
-3. It provides methods (`sayHi`).
-
-This is called *functional class pattern*.
-
-In the functional class pattern, local variables and nested functions inside `User`, that are not assigned to `this`, are visible from inside, but not accessible by the outer code.
-
-So we can easily add internal functions and variables, like `calcAge()` here:
-
-```js run
-function User(name, birthday) {
-*!*
- // only visible from other methods inside User
- function calcAge() {
- return new Date().getFullYear() - birthday.getFullYear();
- }
-*/!*
-
- this.sayHi = function() {
- alert(`${name}, age:${calcAge()}`);
- };
-}
-
-let user = new User("John", new Date(2000, 0, 1));
-user.sayHi(); // John, age:17
-```
-
-In this code variables `name`, `birthday` and the function `calcAge()` are internal, *private* to the object. They are only visible from inside of it.
-
-On the other hand, `sayHi` is the external, *public* method. The external code that creates `user` can access it.
-
-This way we can hide internal implementation details and helper methods from the outer code. Only what's assigned to `this` becomes visible outside.
-
-## Factory class pattern
-
-We can create a class without using `new` at all.
-
-Like this:
-
-```js run
-function User(name, birthday) {
- // only visible from other methods inside User
- function calcAge() {
- return new Date().getFullYear() - birthday.getFullYear();
- }
-
- return {
- sayHi() {
- alert(`${name}, age:${calcAge()}`);
- }
- };
-}
-
-*!*
-let user = User("John", new Date(2000, 0, 1));
-*/!*
-user.sayHi(); // John, age:17
-```
-
-As we can see, the function `User` returns an object with public properties and methods. The only benefit of this method is that we can omit `new`: write `let user = User(...)` instead of `let user = new User(...)`. In other aspects it's almost the same as the functional pattern.
-
-## Prototype-based classes
-
-Prototype-based classes are the most important and generally the best. Functional and factory class patterns are rarely used in practice.
-
-Soon you'll see why.
-
-Here's the same class rewritten using prototypes:
-
-```js run
-function User(name, birthday) {
-*!*
- this._name = name;
- this._birthday = birthday;
-*/!*
-}
-
-*!*
-User.prototype._calcAge = function() {
-*/!*
- return new Date().getFullYear() - this._birthday.getFullYear();
-};
-
-User.prototype.sayHi = function() {
- alert(`${this._name}, age:${this._calcAge()}`);
-};
-
-let user = new User("John", new Date(2000, 0, 1));
-user.sayHi(); // John, age:17
-```
-
-The code structure:
-
-- The constructor `User` only initializes the current object state.
-- Methods are added to `User.prototype`.
-
-As we can see, methods are lexically not inside `function User`, they do not share a common lexical environment. If we declare variables inside `function User`, then they won't be visible to methods.
-
-So, there is a widely known agreement that internal properties and methods are prepended with an underscore `"_"`. Like `_name` or `_calcAge()`. Technically, that's just an agreement, the outer code still can access them. But most developers recognize the meaning of `"_"` and try not to touch prefixed properties and methods in the external code.
-
-Here are the advantages over the functional pattern:
-
-- In the functional pattern, each object has its own copy of every method. We assign a separate copy of `this.sayHi = function() {...}` and other methods in the constructor.
-- In the prototypal pattern, all methods are in `User.prototype` that is shared between all user objects. An object itself only stores the data.
-
-So the prototypal pattern is more memory-efficient.
-
-...But not only that. Prototypes allow us to setup the inheritance in a really efficient way. Built-in JavaScript objects all use prototypes. Also there's a special syntax construct: "class" that provides nice-looking syntax for them. And there's more, so let's go on with them.
-
-## Prototype-based inheritance for classes
-
-Let's say we have two prototype-based classes.
-
-`Rabbit`:
-
-```js
-function Rabbit(name) {
- this.name = name;
-}
-
-Rabbit.prototype.jump = function() {
- alert(`${this.name} jumps!`);
-};
-
-let rabbit = new Rabbit("My rabbit");
-```
-
-
-
-...And `Animal`:
-
-```js
-function Animal(name) {
- this.name = name;
-}
-
-Animal.prototype.eat = function() {
- alert(`${this.name} eats.`);
-};
-
-let animal = new Animal("My animal");
-```
-
-
-
-Right now they are fully independent.
-
-But we'd want `Rabbit` to extend `Animal`. In other words, rabbits should be based on animals, have access to methods of `Animal` and extend them with its own methods.
-
-What does it mean in the language of prototypes?
-
-Right now methods for `rabbit` objects are in `Rabbit.prototype`. We'd like `rabbit` to use `Animal.prototype` as a "fallback", if the method is not found in `Rabbit.prototype`.
-
-So the prototype chain should be `rabbit` -> `Rabbit.prototype` -> `Animal.prototype`.
-
-Like this:
-
-
-
-The code to implement that:
-
-```js run
-// Same Animal as before
-function Animal(name) {
- this.name = name;
-}
-
-// All animals can eat, right?
-Animal.prototype.eat = function() {
- alert(`${this.name} eats.`);
-};
-
-// Same Rabbit as before
-function Rabbit(name) {
- this.name = name;
-}
-
-Rabbit.prototype.jump = function() {
- alert(`${this.name} jumps!`);
-};
-
-*!*
-// setup the inheritance chain
-Rabbit.prototype.__proto__ = Animal.prototype; // (*)
-*/!*
-
-let rabbit = new Rabbit("White Rabbit");
-*!*
-rabbit.eat(); // rabbits can eat too
-*/!*
-rabbit.jump();
-```
-
-The line `(*)` sets up the prototype chain. So that `rabbit` first searches methods in `Rabbit.prototype`, then `Animal.prototype`. And then, just for completeness, let's mention that if the method is not found in `Animal.prototype`, then the search continues in `Object.prototype`, because `Animal.prototype` is a regular plain object, so it inherits from it.
-
-So here's the full picture:
-
-
-
-## Summary
-
-The term "class" comes from the object-oriented programming. In JavaScript it usually means the functional class pattern or the prototypal pattern. The prototypal pattern is more powerful and memory-efficient, so it's recommended to stick to it.
-
-According to the prototypal pattern:
-1. Methods are stored in `Class.prototype`.
-2. Prototypes inherit from each other.
-
-In the next chapter we'll study `class` keyword and construct. It allows to write prototypal classes shorter and provides some additional benefits.
diff --git a/1-js/09-classes/01-class-patterns/class-inheritance-rabbit-animal-2.png b/1-js/09-classes/01-class-patterns/class-inheritance-rabbit-animal-2.png
deleted file mode 100644
index 86b1a585ba..0000000000
Binary files a/1-js/09-classes/01-class-patterns/class-inheritance-rabbit-animal-2.png and /dev/null differ
diff --git a/1-js/09-classes/01-class-patterns/class-inheritance-rabbit-animal-2@2x.png b/1-js/09-classes/01-class-patterns/class-inheritance-rabbit-animal-2@2x.png
deleted file mode 100644
index f44bfb1d9a..0000000000
Binary files a/1-js/09-classes/01-class-patterns/class-inheritance-rabbit-animal-2@2x.png and /dev/null differ
diff --git a/1-js/09-classes/01-class-patterns/class-inheritance-rabbit-animal.png b/1-js/09-classes/01-class-patterns/class-inheritance-rabbit-animal.png
deleted file mode 100644
index 0da6479d76..0000000000
Binary files a/1-js/09-classes/01-class-patterns/class-inheritance-rabbit-animal.png and /dev/null differ
diff --git a/1-js/09-classes/01-class-patterns/class-inheritance-rabbit-animal@2x.png b/1-js/09-classes/01-class-patterns/class-inheritance-rabbit-animal@2x.png
deleted file mode 100644
index ebe8c0325c..0000000000
Binary files a/1-js/09-classes/01-class-patterns/class-inheritance-rabbit-animal@2x.png and /dev/null differ
diff --git a/1-js/09-classes/01-class-patterns/rabbit-animal-independent-1.png b/1-js/09-classes/01-class-patterns/rabbit-animal-independent-1.png
deleted file mode 100644
index f1d3121829..0000000000
Binary files a/1-js/09-classes/01-class-patterns/rabbit-animal-independent-1.png and /dev/null differ
diff --git a/1-js/09-classes/01-class-patterns/rabbit-animal-independent-1@2x.png b/1-js/09-classes/01-class-patterns/rabbit-animal-independent-1@2x.png
deleted file mode 100644
index 29c878ea64..0000000000
Binary files a/1-js/09-classes/01-class-patterns/rabbit-animal-independent-1@2x.png and /dev/null differ
diff --git a/1-js/09-classes/01-class-patterns/rabbit-animal-independent-2.png b/1-js/09-classes/01-class-patterns/rabbit-animal-independent-2.png
deleted file mode 100644
index bae44e5729..0000000000
Binary files a/1-js/09-classes/01-class-patterns/rabbit-animal-independent-2.png and /dev/null differ
diff --git a/1-js/09-classes/01-class-patterns/rabbit-animal-independent-2@2x.png b/1-js/09-classes/01-class-patterns/rabbit-animal-independent-2@2x.png
deleted file mode 100644
index 6197bd29bb..0000000000
Binary files a/1-js/09-classes/01-class-patterns/rabbit-animal-independent-2@2x.png and /dev/null differ
diff --git a/1-js/09-classes/01-class/1-rewrite-to-class/_js.view/solution.js b/1-js/09-classes/01-class/1-rewrite-to-class/_js.view/solution.js
new file mode 100644
index 0000000000..0b31cf334e
--- /dev/null
+++ b/1-js/09-classes/01-class/1-rewrite-to-class/_js.view/solution.js
@@ -0,0 +1,38 @@
+class Clock {
+ constructor({ template }) {
+ this.template = template;
+ }
+
+ render() {
+ let date = new Date();
+
+ let hours = date.getHours();
+ if (hours < 10) hours = '0' + hours;
+
+ let mins = date.getMinutes();
+ if (mins < 10) mins = '0' + mins;
+
+ let secs = date.getSeconds();
+ if (secs < 10) secs = '0' + secs;
+
+ let output = this.template
+ .replace('h', hours)
+ .replace('m', mins)
+ .replace('s', secs);
+
+ console.log(output);
+ }
+
+ stop() {
+ clearInterval(this.timer);
+ }
+
+ start() {
+ this.render();
+ this.timer = setInterval(() => this.render(), 1000);
+ }
+}
+
+
+let clock = new Clock({template: 'h:m:s'});
+clock.start();
diff --git a/1-js/09-classes/01-class/1-rewrite-to-class/_js.view/source.js b/1-js/09-classes/01-class/1-rewrite-to-class/_js.view/source.js
new file mode 100644
index 0000000000..f1749c8ba5
--- /dev/null
+++ b/1-js/09-classes/01-class/1-rewrite-to-class/_js.view/source.js
@@ -0,0 +1,37 @@
+function Clock({ template }) {
+
+ let timer;
+
+ function render() {
+ let date = new Date();
+
+ let hours = date.getHours();
+ if (hours < 10) hours = '0' + hours;
+
+ let mins = date.getMinutes();
+ if (mins < 10) mins = '0' + mins;
+
+ let secs = date.getSeconds();
+ if (secs < 10) secs = '0' + secs;
+
+ let output = template
+ .replace('h', hours)
+ .replace('m', mins)
+ .replace('s', secs);
+
+ console.log(output);
+ }
+
+ this.stop = function() {
+ clearInterval(timer);
+ };
+
+ this.start = function() {
+ render();
+ timer = setInterval(render, 1000);
+ };
+
+}
+
+let clock = new Clock({template: 'h:m:s'});
+clock.start();
diff --git a/1-js/11-async/01-callbacks/01-animate-circle-callback/solution.md b/1-js/09-classes/01-class/1-rewrite-to-class/solution.md
similarity index 100%
rename from 1-js/11-async/01-callbacks/01-animate-circle-callback/solution.md
rename to 1-js/09-classes/01-class/1-rewrite-to-class/solution.md
diff --git a/1-js/09-classes/01-class/1-rewrite-to-class/task.md b/1-js/09-classes/01-class/1-rewrite-to-class/task.md
new file mode 100644
index 0000000000..4477de6799
--- /dev/null
+++ b/1-js/09-classes/01-class/1-rewrite-to-class/task.md
@@ -0,0 +1,9 @@
+importance: 5
+
+---
+
+# Rewrite to class
+
+The `Clock` class (see the sandbox) is written in functional style. Rewrite it in the "class" syntax.
+
+P.S. The clock ticks in the console, open it to see.
diff --git a/1-js/09-classes/01-class/article.md b/1-js/09-classes/01-class/article.md
new file mode 100644
index 0000000000..135d24929b
--- /dev/null
+++ b/1-js/09-classes/01-class/article.md
@@ -0,0 +1,428 @@
+
+# Class basic syntax
+
+```quote author="Wikipedia"
+In object-oriented programming, a *class* is an extensible program-code-template for creating objects, providing initial values for state (member variables) and implementations of behavior (member functions or methods).
+```
+
+In practice, we often need to create many objects of the same kind, like users, or goods or whatever.
+
+As we already know from the chapter , `new function` can help with that.
+
+But in the modern JavaScript, there's a more advanced "class" construct, that introduces great new features which are useful for object-oriented programming.
+
+## The "class" syntax
+
+The basic syntax is:
+```js
+class MyClass {
+ // class methods
+ constructor() { ... }
+ method1() { ... }
+ method2() { ... }
+ method3() { ... }
+ ...
+}
+```
+
+Then use `new MyClass()` to create a new object with all the listed methods.
+
+The `constructor()` method is called automatically by `new`, so we can initialize the object there.
+
+For example:
+
+```js run
+class User {
+
+ constructor(name) {
+ this.name = name;
+ }
+
+ sayHi() {
+ alert(this.name);
+ }
+
+}
+
+// Usage:
+let user = new User("John");
+user.sayHi();
+```
+
+When `new User("John")` is called:
+1. A new object is created.
+2. The `constructor` runs with the given argument and assigns it to `this.name`.
+
+...Then we can call object methods, such as `user.sayHi()`.
+
+
+```warn header="No comma between class methods"
+A common pitfall for novice developers is to put a comma between class methods, which would result in a syntax error.
+
+The notation here is not to be confused with object literals. Within the class, no commas are required.
+```
+
+## What is a class?
+
+So, what exactly is a `class`? That's not an entirely new language-level entity, as one might think.
+
+Let's unveil any magic and see what a class really is. That'll help in understanding many complex aspects.
+
+In JavaScript, a class is a kind of function.
+
+Here, take a look:
+
+```js run
+class User {
+ constructor(name) { this.name = name; }
+ sayHi() { alert(this.name); }
+}
+
+// proof: User is a function
+*!*
+alert(typeof User); // function
+*/!*
+```
+
+What `class User {...}` construct really does is:
+
+1. Creates a function named `User`, that becomes the result of the class declaration. The function code is taken from the `constructor` method (assumed empty if we don't write such method).
+2. Stores class methods, such as `sayHi`, in `User.prototype`.
+
+After `new User` object is created, when we call its method, it's taken from the prototype, just as described in the chapter . So the object has access to class methods.
+
+We can illustrate the result of `class User` declaration as:
+
+
+
+Here's the code to introspect it:
+
+```js run
+class User {
+ constructor(name) { this.name = name; }
+ sayHi() { alert(this.name); }
+}
+
+// class is a function
+alert(typeof User); // function
+
+// ...or, more precisely, the constructor method
+alert(User === User.prototype.constructor); // true
+
+// The methods are in User.prototype, e.g:
+alert(User.prototype.sayHi); // the code of the sayHi method
+
+// there are exactly two methods in the prototype
+alert(Object.getOwnPropertyNames(User.prototype)); // constructor, sayHi
+```
+
+## Not just a syntactic sugar
+
+Sometimes people say that `class` is a "syntactic sugar" (syntax that is designed to make things easier to read, but doesn't introduce anything new), because we could actually declare the same thing without using the `class` keyword at all:
+
+```js run
+// rewriting class User in pure functions
+
+// 1. Create constructor function
+function User(name) {
+ this.name = name;
+}
+// a function prototype has "constructor" property by default,
+// so we don't need to create it
+
+// 2. Add the method to prototype
+User.prototype.sayHi = function() {
+ alert(this.name);
+};
+
+// Usage:
+let user = new User("John");
+user.sayHi();
+```
+
+The result of this definition is about the same. So, there are indeed reasons why `class` can be considered a syntactic sugar to define a constructor together with its prototype methods.
+
+Still, there are important differences.
+
+1. First, a function created by `class` is labelled by a special internal property `[[IsClassConstructor]]: true`. So it's not entirely the same as creating it manually.
+
+ The language checks for that property in a variety of places. For example, unlike a regular function, it must be called with `new`:
+
+ ```js run
+ class User {
+ constructor() {}
+ }
+
+ alert(typeof User); // function
+ User(); // Error: Class constructor User cannot be invoked without 'new'
+ ```
+
+ Also, a string representation of a class constructor in most JavaScript engines starts with the "class..."
+
+ ```js run
+ class User {
+ constructor() {}
+ }
+
+ alert(User); // class User { ... }
+ ```
+ There are other differences, we'll see them soon.
+
+2. Class methods are non-enumerable.
+ A class definition sets `enumerable` flag to `false` for all methods in the `"prototype"`.
+
+ That's good, because if we `for..in` over an object, we usually don't want its class methods.
+
+3. Classes always `use strict`.
+ All code inside the class construct is automatically in strict mode.
+
+Besides, `class` syntax brings many other features that we'll explore later.
+
+## Class Expression
+
+Just like functions, classes can be defined inside another expression, passed around, returned, assigned, etc.
+
+Here's an example of a class expression:
+
+```js
+let User = class {
+ sayHi() {
+ alert("Hello");
+ }
+};
+```
+
+Similar to Named Function Expressions, class expressions may have a name.
+
+If a class expression has a name, it's visible inside the class only:
+
+```js run
+// "Named Class Expression"
+// (no such term in the spec, but that's similar to Named Function Expression)
+let User = class *!*MyClass*/!* {
+ sayHi() {
+ alert(MyClass); // MyClass name is visible only inside the class
+ }
+};
+
+new User().sayHi(); // works, shows MyClass definition
+
+alert(MyClass); // error, MyClass name isn't visible outside of the class
+```
+
+We can even make classes dynamically "on-demand", like this:
+
+```js run
+function makeClass(phrase) {
+ // declare a class and return it
+ return class {
+ sayHi() {
+ alert(phrase);
+ }
+ };
+}
+
+// Create a new class
+let User = makeClass("Hello");
+
+new User().sayHi(); // Hello
+```
+
+
+## Getters/setters
+
+Just like literal objects, classes may include getters/setters, computed properties etc.
+
+Here's an example for `user.name` implemented using `get/set`:
+
+```js run
+class User {
+
+ constructor(name) {
+ // invokes the setter
+ this.name = name;
+ }
+
+*!*
+ get name() {
+*/!*
+ return this._name;
+ }
+
+*!*
+ set name(value) {
+*/!*
+ if (value.length < 4) {
+ alert("Name is too short.");
+ return;
+ }
+ this._name = value;
+ }
+
+}
+
+let user = new User("John");
+alert(user.name); // John
+
+user = new User(""); // Name is too short.
+```
+
+Technically, such class declaration works by creating getters and setters in `User.prototype`.
+
+## Computed names [...]
+
+Here's an example with a computed method name using brackets `[...]`:
+
+```js run
+class User {
+
+*!*
+ ['say' + 'Hi']() {
+*/!*
+ alert("Hello");
+ }
+
+}
+
+new User().sayHi();
+```
+
+Such features are easy to remember, as they resemble that of literal objects.
+
+## Class fields
+
+```warn header="Old browsers may need a polyfill"
+Class fields are a recent addition to the language.
+```
+
+Previously, our classes only had methods.
+
+"Class fields" is a syntax that allows to add any properties.
+
+For instance, let's add `name` property to `class User`:
+
+```js run
+class User {
+*!*
+ name = "John";
+*/!*
+
+ sayHi() {
+ alert(`Hello, ${this.name}!`);
+ }
+}
+
+new User().sayHi(); // Hello, John!
+```
+
+So, we just write " = " in the declaration, and that's it.
+
+The important difference of class fields is that they are set on individual objects, not `User.prototype`:
+
+```js run
+class User {
+*!*
+ name = "John";
+*/!*
+}
+
+let user = new User();
+alert(user.name); // John
+alert(User.prototype.name); // undefined
+```
+
+We can also assign values using more complex expressions and function calls:
+
+```js run
+class User {
+*!*
+ name = prompt("Name, please?", "John");
+*/!*
+}
+
+let user = new User();
+alert(user.name); // John
+```
+
+
+### Making bound methods with class fields
+
+As demonstrated in the chapter functions in JavaScript have a dynamic `this`. It depends on the context of the call.
+
+So if an object method is passed around and called in another context, `this` won't be a reference to its object any more.
+
+For instance, this code will show `undefined`:
+
+```js run
+class Button {
+ constructor(value) {
+ this.value = value;
+ }
+
+ click() {
+ alert(this.value);
+ }
+}
+
+let button = new Button("hello");
+
+*!*
+setTimeout(button.click, 1000); // undefined
+*/!*
+```
+
+The problem is called "losing `this`".
+
+There are two approaches to fixing it, as discussed in the chapter :
+
+1. Pass a wrapper-function, such as `setTimeout(() => button.click(), 1000)`.
+2. Bind the method to object, e.g. in the constructor.
+
+Class fields provide another, quite elegant syntax:
+
+```js run
+class Button {
+ constructor(value) {
+ this.value = value;
+ }
+*!*
+ click = () => {
+ alert(this.value);
+ }
+*/!*
+}
+
+let button = new Button("hello");
+
+setTimeout(button.click, 1000); // hello
+```
+
+The class field `click = () => {...}` is created on a per-object basis, there's a separate function for each `Button` object, with `this` inside it referencing that object. We can pass `button.click` around anywhere, and the value of `this` will always be correct.
+
+That's especially useful in browser environment, for event listeners.
+
+## Summary
+
+The basic class syntax looks like this:
+
+```js
+class MyClass {
+ prop = value; // property
+
+ constructor(...) { // constructor
+ // ...
+ }
+
+ method(...) {} // method
+
+ get something(...) {} // getter method
+ set something(...) {} // setter method
+
+ [Symbol.iterator]() {} // method with computed name (symbol here)
+ // ...
+}
+```
+
+`MyClass` is technically a function (the one that we provide as `constructor`), while methods, getters and setters are written to `MyClass.prototype`.
+
+In the next chapters we'll learn more about classes, including inheritance and other features.
diff --git a/1-js/09-classes/01-class/class-user.svg b/1-js/09-classes/01-class/class-user.svg
new file mode 100644
index 0000000000..418d71d187
--- /dev/null
+++ b/1-js/09-classes/01-class/class-user.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/09-classes/03-class-inheritance/1-class-constructor-error/solution.md b/1-js/09-classes/02-class-inheritance/1-class-constructor-error/solution.md
similarity index 100%
rename from 1-js/09-classes/03-class-inheritance/1-class-constructor-error/solution.md
rename to 1-js/09-classes/02-class-inheritance/1-class-constructor-error/solution.md
diff --git a/1-js/09-classes/03-class-inheritance/1-class-constructor-error/task.md b/1-js/09-classes/02-class-inheritance/1-class-constructor-error/task.md
similarity index 100%
rename from 1-js/09-classes/03-class-inheritance/1-class-constructor-error/task.md
rename to 1-js/09-classes/02-class-inheritance/1-class-constructor-error/task.md
diff --git a/1-js/09-classes/03-class-inheritance/2-clock-class-extended/solution.md b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.md
similarity index 100%
rename from 1-js/09-classes/03-class-inheritance/2-clock-class-extended/solution.md
rename to 1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.md
diff --git a/1-js/09-classes/02-class/1-rewrite-to-class/solution.view/clock.js b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.view/clock.js
similarity index 100%
rename from 1-js/09-classes/02-class/1-rewrite-to-class/solution.view/clock.js
rename to 1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.view/clock.js
diff --git a/1-js/09-classes/03-class-inheritance/2-clock-class-extended/solution.view/extended-clock.js b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.view/extended-clock.js
similarity index 84%
rename from 1-js/09-classes/03-class-inheritance/2-clock-class-extended/solution.view/extended-clock.js
rename to 1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.view/extended-clock.js
index ca613ca5e5..be2053cfcf 100644
--- a/1-js/09-classes/03-class-inheritance/2-clock-class-extended/solution.view/extended-clock.js
+++ b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.view/extended-clock.js
@@ -1,7 +1,7 @@
class ExtendedClock extends Clock {
constructor(options) {
super(options);
- let { precision=1000 } = options;
+ let { precision = 1000 } = options;
this.precision = precision;
}
diff --git a/1-js/09-classes/03-class-inheritance/2-clock-class-extended/solution.view/index.html b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.view/index.html
similarity index 100%
rename from 1-js/09-classes/03-class-inheritance/2-clock-class-extended/solution.view/index.html
rename to 1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.view/index.html
diff --git a/1-js/09-classes/03-class-inheritance/2-clock-class-extended/solution.view/clock.js b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/source.view/clock.js
similarity index 100%
rename from 1-js/09-classes/03-class-inheritance/2-clock-class-extended/solution.view/clock.js
rename to 1-js/09-classes/02-class-inheritance/2-clock-class-extended/source.view/clock.js
diff --git a/1-js/09-classes/03-class-inheritance/2-clock-class-extended/source.view/index.html b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/source.view/index.html
similarity index 100%
rename from 1-js/09-classes/03-class-inheritance/2-clock-class-extended/source.view/index.html
rename to 1-js/09-classes/02-class-inheritance/2-clock-class-extended/source.view/index.html
diff --git a/1-js/09-classes/03-class-inheritance/2-clock-class-extended/task.md b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/task.md
similarity index 100%
rename from 1-js/09-classes/03-class-inheritance/2-clock-class-extended/task.md
rename to 1-js/09-classes/02-class-inheritance/2-clock-class-extended/task.md
diff --git a/1-js/09-classes/02-class-inheritance/animal-rabbit-extends.svg b/1-js/09-classes/02-class-inheritance/animal-rabbit-extends.svg
new file mode 100644
index 0000000000..63b5a18a19
--- /dev/null
+++ b/1-js/09-classes/02-class-inheritance/animal-rabbit-extends.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/09-classes/02-class-inheritance/article.md b/1-js/09-classes/02-class-inheritance/article.md
new file mode 100644
index 0000000000..464042d823
--- /dev/null
+++ b/1-js/09-classes/02-class-inheritance/article.md
@@ -0,0 +1,627 @@
+
+# Class inheritance
+
+Class inheritance is a way for one class to extend another class.
+
+So we can create new functionality on top of the existing.
+
+## The "extends" keyword
+
+Let's say we have class `Animal`:
+
+```js
+class Animal {
+ constructor(name) {
+ this.speed = 0;
+ this.name = name;
+ }
+ run(speed) {
+ this.speed = speed;
+ alert(`${this.name} runs with speed ${this.speed}.`);
+ }
+ stop() {
+ this.speed = 0;
+ alert(`${this.name} stands still.`);
+ }
+}
+
+let animal = new Animal("My animal");
+```
+
+Here's how we can represent `animal` object and `Animal` class graphically:
+
+
+
+...And we would like to create another `class Rabbit`.
+
+As rabbits are animals, `Rabbit` class should be based on `Animal`, have access to animal methods, so that rabbits can do what "generic" animals can do.
+
+The syntax to extend another class is: `class Child extends Parent`.
+
+Let's create `class Rabbit` that inherits from `Animal`:
+
+```js
+*!*
+class Rabbit extends Animal {
+*/!*
+ hide() {
+ alert(`${this.name} hides!`);
+ }
+}
+
+let rabbit = new Rabbit("White Rabbit");
+
+rabbit.run(5); // White Rabbit runs with speed 5.
+rabbit.hide(); // White Rabbit hides!
+```
+
+Object of `Rabbit` class have access both to `Rabbit` methods, such as `rabbit.hide()`, and also to `Animal` methods, such as `rabbit.run()`.
+
+Internally, `extends` keyword works using the good old prototype mechanics. It sets `Rabbit.prototype.[[Prototype]]` to `Animal.prototype`. So, if a method is not found in `Rabbit.prototype`, JavaScript takes it from `Animal.prototype`.
+
+
+
+For instance, to find `rabbit.run` method, the engine checks (bottom-up on the picture):
+1. The `rabbit` object (has no `run`).
+2. Its prototype, that is `Rabbit.prototype` (has `hide`, but not `run`).
+3. Its prototype, that is (due to `extends`) `Animal.prototype`, that finally has the `run` method.
+
+As we can recall from the chapter , JavaScript itself uses prototypal inheritance for built-in objects. E.g. `Date.prototype.[[Prototype]]` is `Object.prototype`. That's why dates have access to generic object methods.
+
+````smart header="Any expression is allowed after `extends`"
+Class syntax allows to specify not just a class, but any expression after `extends`.
+
+For instance, a function call that generates the parent class:
+
+```js run
+function f(phrase) {
+ return class {
+ sayHi() { alert(phrase); }
+ };
+}
+
+*!*
+class User extends f("Hello") {}
+*/!*
+
+new User().sayHi(); // Hello
+```
+Here `class User` inherits from the result of `f("Hello")`.
+
+That may be useful for advanced programming patterns when we use functions to generate classes depending on many conditions and can inherit from them.
+````
+
+## Overriding a method
+
+Now let's move forward and override a method. By default, all methods that are not specified in `class Rabbit` are taken directly "as is" from `class Animal`.
+
+But if we specify our own method in `Rabbit`, such as `stop()` then it will be used instead:
+
+```js
+class Rabbit extends Animal {
+ stop() {
+ // ...now this will be used for rabbit.stop()
+ // instead of stop() from class Animal
+ }
+}
+```
+
+Usually, however, we don't want to totally replace a parent method, but rather to build on top of it to tweak or extend its functionality. We do something in our method, but call the parent method before/after it or in the process.
+
+Classes provide `"super"` keyword for that.
+
+- `super.method(...)` to call a parent method.
+- `super(...)` to call a parent constructor (inside our constructor only).
+
+For instance, let our rabbit autohide when stopped:
+
+```js run
+class Animal {
+
+ constructor(name) {
+ this.speed = 0;
+ this.name = name;
+ }
+
+ run(speed) {
+ this.speed = speed;
+ alert(`${this.name} runs with speed ${this.speed}.`);
+ }
+
+ stop() {
+ this.speed = 0;
+ alert(`${this.name} stands still.`);
+ }
+
+}
+
+class Rabbit extends Animal {
+ hide() {
+ alert(`${this.name} hides!`);
+ }
+
+*!*
+ stop() {
+ super.stop(); // call parent stop
+ this.hide(); // and then hide
+ }
+*/!*
+}
+
+let rabbit = new Rabbit("White Rabbit");
+
+rabbit.run(5); // White Rabbit runs with speed 5.
+rabbit.stop(); // White Rabbit stands still. White Rabbit hides!
+```
+
+Now `Rabbit` has the `stop` method that calls the parent `super.stop()` in the process.
+
+````smart header="Arrow functions have no `super`"
+As was mentioned in the chapter , arrow functions do not have `super`.
+
+If accessed, it's taken from the outer function. For instance:
+
+```js
+class Rabbit extends Animal {
+ stop() {
+ setTimeout(() => super.stop(), 1000); // call parent stop after 1sec
+ }
+}
+```
+
+The `super` in the arrow function is the same as in `stop()`, so it works as intended. If we specified a "regular" function here, there would be an error:
+
+```js
+// Unexpected super
+setTimeout(function() { super.stop() }, 1000);
+```
+````
+
+## Overriding constructor
+
+With constructors it gets a little bit tricky.
+
+Until now, `Rabbit` did not have its own `constructor`.
+
+According to the [specification](https://tc39.github.io/ecma262/#sec-runtime-semantics-classdefinitionevaluation), if a class extends another class and has no `constructor`, then the following "empty" `constructor` is generated:
+
+```js
+class Rabbit extends Animal {
+ // generated for extending classes without own constructors
+*!*
+ constructor(...args) {
+ super(...args);
+ }
+*/!*
+}
+```
+
+As we can see, it basically calls the parent `constructor` passing it all the arguments. That happens if we don't write a constructor of our own.
+
+Now let's add a custom constructor to `Rabbit`. It will specify the `earLength` in addition to `name`:
+
+```js run
+class Animal {
+ constructor(name) {
+ this.speed = 0;
+ this.name = name;
+ }
+ // ...
+}
+
+class Rabbit extends Animal {
+
+*!*
+ constructor(name, earLength) {
+ this.speed = 0;
+ this.name = name;
+ this.earLength = earLength;
+ }
+*/!*
+
+ // ...
+}
+
+*!*
+// Doesn't work!
+let rabbit = new Rabbit("White Rabbit", 10); // Error: this is not defined.
+*/!*
+```
+
+Whoops! We've got an error. Now we can't create rabbits. What went wrong?
+
+The short answer is:
+
+- **Constructors in inheriting classes must call `super(...)`, and (!) do it before using `this`.**
+
+...But why? What's going on here? Indeed, the requirement seems strange.
+
+Of course, there's an explanation. Let's get into details, so you'll really understand what's going on.
+
+In JavaScript, there's a distinction between a constructor function of an inheriting class (so-called "derived constructor") and other functions. A derived constructor has a special internal property `[[ConstructorKind]]:"derived"`. That's a special internal label.
+
+That label affects its behavior with `new`.
+
+- When a regular function is executed with `new`, it creates an empty object and assigns it to `this`.
+- But when a derived constructor runs, it doesn't do this. It expects the parent constructor to do this job.
+
+So a derived constructor must call `super` in order to execute its parent (base) constructor, otherwise the object for `this` won't be created. And we'll get an error.
+
+For the `Rabbit` constructor to work, it needs to call `super()` before using `this`, like here:
+
+```js run
+class Animal {
+
+ constructor(name) {
+ this.speed = 0;
+ this.name = name;
+ }
+
+ // ...
+}
+
+class Rabbit extends Animal {
+
+ constructor(name, earLength) {
+*!*
+ super(name);
+*/!*
+ this.earLength = earLength;
+ }
+
+ // ...
+}
+
+*!*
+// now fine
+let rabbit = new Rabbit("White Rabbit", 10);
+alert(rabbit.name); // White Rabbit
+alert(rabbit.earLength); // 10
+*/!*
+```
+
+### Overriding class fields: a tricky note
+
+```warn header="Advanced note"
+This note assumes you have a certain experience with classes, maybe in other programming languages.
+
+It provides better insight into the language and also explains the behavior that might be a source of bugs (but not very often).
+
+If you find it difficult to understand, just go on, continue reading, then return to it some time later.
+```
+
+We can override not only methods, but also class fields.
+
+Although, there's a tricky behavior when we access an overridden field in parent constructor, quite different from most other programming languages.
+
+Consider this example:
+
+```js run
+class Animal {
+ name = 'animal';
+
+ constructor() {
+ alert(this.name); // (*)
+ }
+}
+
+class Rabbit extends Animal {
+ name = 'rabbit';
+}
+
+new Animal(); // animal
+*!*
+new Rabbit(); // animal
+*/!*
+```
+
+Here, class `Rabbit` extends `Animal` and overrides the `name` field with its own value.
+
+There's no own constructor in `Rabbit`, so `Animal` constructor is called.
+
+What's interesting is that in both cases: `new Animal()` and `new Rabbit()`, the `alert` in the line `(*)` shows `animal`.
+
+**In other words, the parent constructor always uses its own field value, not the overridden one.**
+
+What's odd about it?
+
+If it's not clear yet, please compare with methods.
+
+Here's the same code, but instead of `this.name` field we call `this.showName()` method:
+
+```js run
+class Animal {
+ showName() { // instead of this.name = 'animal'
+ alert('animal');
+ }
+
+ constructor() {
+ this.showName(); // instead of alert(this.name);
+ }
+}
+
+class Rabbit extends Animal {
+ showName() {
+ alert('rabbit');
+ }
+}
+
+new Animal(); // animal
+*!*
+new Rabbit(); // rabbit
+*/!*
+```
+
+Please note: now the output is different.
+
+And that's what we naturally expect. When the parent constructor is called in the derived class, it uses the overridden method.
+
+...But for class fields it's not so. As said, the parent constructor always uses the parent field.
+
+Why is there a difference?
+
+Well, the reason is the field initialization order. The class field is initialized:
+- Before constructor for the base class (that doesn't extend anything),
+- Immediately after `super()` for the derived class.
+
+In our case, `Rabbit` is the derived class. There's no `constructor()` in it. As said previously, that's the same as if there was an empty constructor with only `super(...args)`.
+
+So, `new Rabbit()` calls `super()`, thus executing the parent constructor, and (per the rule for derived classes) only after that its class fields are initialized. At the time of the parent constructor execution, there are no `Rabbit` class fields yet, that's why `Animal` fields are used.
+
+This subtle difference between fields and methods is specific to JavaScript.
+
+Luckily, this behavior only reveals itself if an overridden field is used in the parent constructor. Then it may be difficult to understand what's going on, so we're explaining it here.
+
+If it becomes a problem, one can fix it by using methods or getters/setters instead of fields.
+
+## Super: internals, [[HomeObject]]
+
+```warn header="Advanced information"
+If you're reading the tutorial for the first time - this section may be skipped.
+
+It's about the internal mechanisms behind inheritance and `super`.
+```
+
+Let's get a little deeper under the hood of `super`. We'll see some interesting things along the way.
+
+First to say, from all that we've learned till now, it's impossible for `super` to work at all!
+
+Yeah, indeed, let's ask ourselves, how it should technically work? When an object method runs, it gets the current object as `this`. If we call `super.method()` then, the engine needs to get the `method` from the prototype of the current object. But how?
+
+The task may seem simple, but it isn't. The engine knows the current object `this`, so it could get the parent `method` as `this.__proto__.method`. Unfortunately, such a "naive" solution won't work.
+
+Let's demonstrate the problem. Without classes, using plain objects for the sake of simplicity.
+
+You may skip this part and go below to the `[[HomeObject]]` subsection if you don't want to know the details. That won't harm. Or read on if you're interested in understanding things in-depth.
+
+In the example below, `rabbit.__proto__ = animal`. Now let's try: in `rabbit.eat()` we'll call `animal.eat()`, using `this.__proto__`:
+
+```js run
+let animal = {
+ name: "Animal",
+ eat() {
+ alert(`${this.name} eats.`);
+ }
+};
+
+let rabbit = {
+ __proto__: animal,
+ name: "Rabbit",
+ eat() {
+*!*
+ // that's how super.eat() could presumably work
+ this.__proto__.eat.call(this); // (*)
+*/!*
+ }
+};
+
+rabbit.eat(); // Rabbit eats.
+```
+
+At the line `(*)` we take `eat` from the prototype (`animal`) and call it in the context of the current object. Please note that `.call(this)` is important here, because a simple `this.__proto__.eat()` would execute parent `eat` in the context of the prototype, not the current object.
+
+And in the code above it actually works as intended: we have the correct `alert`.
+
+Now let's add one more object to the chain. We'll see how things break:
+
+```js run
+let animal = {
+ name: "Animal",
+ eat() {
+ alert(`${this.name} eats.`);
+ }
+};
+
+let rabbit = {
+ __proto__: animal,
+ eat() {
+ // ...bounce around rabbit-style and call parent (animal) method
+ this.__proto__.eat.call(this); // (*)
+ }
+};
+
+let longEar = {
+ __proto__: rabbit,
+ eat() {
+ // ...do something with long ears and call parent (rabbit) method
+ this.__proto__.eat.call(this); // (**)
+ }
+};
+
+*!*
+longEar.eat(); // Error: Maximum call stack size exceeded
+*/!*
+```
+
+The code doesn't work anymore! We can see the error trying to call `longEar.eat()`.
+
+It may be not that obvious, but if we trace `longEar.eat()` call, then we can see why. In both lines `(*)` and `(**)` the value of `this` is the current object (`longEar`). That's essential: all object methods get the current object as `this`, not a prototype or something.
+
+So, in both lines `(*)` and `(**)` the value of `this.__proto__` is exactly the same: `rabbit`. They both call `rabbit.eat` without going up the chain in the endless loop.
+
+Here's the picture of what happens:
+
+
+
+1. Inside `longEar.eat()`, the line `(**)` calls `rabbit.eat` providing it with `this=longEar`.
+ ```js
+ // inside longEar.eat() we have this = longEar
+ this.__proto__.eat.call(this) // (**)
+ // becomes
+ longEar.__proto__.eat.call(this)
+ // that is
+ rabbit.eat.call(this);
+ ```
+2. Then in the line `(*)` of `rabbit.eat`, we'd like to pass the call even higher in the chain, but `this=longEar`, so `this.__proto__.eat` is again `rabbit.eat`!
+
+ ```js
+ // inside rabbit.eat() we also have this = longEar
+ this.__proto__.eat.call(this) // (*)
+ // becomes
+ longEar.__proto__.eat.call(this)
+ // or (again)
+ rabbit.eat.call(this);
+ ```
+
+3. ...So `rabbit.eat` calls itself in the endless loop, because it can't ascend any further.
+
+The problem can't be solved by using `this` alone.
+
+### `[[HomeObject]]`
+
+To provide the solution, JavaScript adds one more special internal property for functions: `[[HomeObject]]`.
+
+When a function is specified as a class or object method, its `[[HomeObject]]` property becomes that object.
+
+Then `super` uses it to resolve the parent prototype and its methods.
+
+Let's see how it works, first with plain objects:
+
+```js run
+let animal = {
+ name: "Animal",
+ eat() { // animal.eat.[[HomeObject]] == animal
+ alert(`${this.name} eats.`);
+ }
+};
+
+let rabbit = {
+ __proto__: animal,
+ name: "Rabbit",
+ eat() { // rabbit.eat.[[HomeObject]] == rabbit
+ super.eat();
+ }
+};
+
+let longEar = {
+ __proto__: rabbit,
+ name: "Long Ear",
+ eat() { // longEar.eat.[[HomeObject]] == longEar
+ super.eat();
+ }
+};
+
+*!*
+// works correctly
+longEar.eat(); // Long Ear eats.
+*/!*
+```
+
+It works as intended, due to `[[HomeObject]]` mechanics. A method, such as `longEar.eat`, knows its `[[HomeObject]]` and takes the parent method from its prototype. Without any use of `this`.
+
+### Methods are not "free"
+
+As we've known before, generally functions are "free", not bound to objects in JavaScript. So they can be copied between objects and called with another `this`.
+
+The very existence of `[[HomeObject]]` violates that principle, because methods remember their objects. `[[HomeObject]]` can't be changed, so this bond is forever.
+
+The only place in the language where `[[HomeObject]]` is used -- is `super`. So, if a method does not use `super`, then we can still consider it free and copy between objects. But with `super` things may go wrong.
+
+Here's the demo of a wrong `super` result after copying:
+
+```js run
+let animal = {
+ sayHi() {
+ alert(`I'm an animal`);
+ }
+};
+
+// rabbit inherits from animal
+let rabbit = {
+ __proto__: animal,
+ sayHi() {
+ super.sayHi();
+ }
+};
+
+let plant = {
+ sayHi() {
+ alert("I'm a plant");
+ }
+};
+
+// tree inherits from plant
+let tree = {
+ __proto__: plant,
+*!*
+ sayHi: rabbit.sayHi // (*)
+*/!*
+};
+
+*!*
+tree.sayHi(); // I'm an animal (?!?)
+*/!*
+```
+
+A call to `tree.sayHi()` shows "I'm an animal". Definitely wrong.
+
+The reason is simple:
+- In the line `(*)`, the method `tree.sayHi` was copied from `rabbit`. Maybe we just wanted to avoid code duplication?
+- Its `[[HomeObject]]` is `rabbit`, as it was created in `rabbit`. There's no way to change `[[HomeObject]]`.
+- The code of `tree.sayHi()` has `super.sayHi()` inside. It goes up from `rabbit` and takes the method from `animal`.
+
+Here's the diagram of what happens:
+
+
+
+### Methods, not function properties
+
+`[[HomeObject]]` is defined for methods both in classes and in plain objects. But for objects, methods must be specified exactly as `method()`, not as `"method: function()"`.
+
+The difference may be non-essential for us, but it's important for JavaScript.
+
+In the example below a non-method syntax is used for comparison. `[[HomeObject]]` property is not set and the inheritance doesn't work:
+
+```js run
+let animal = {
+ eat: function() { // intentionally writing like this instead of eat() {...
+ // ...
+ }
+};
+
+let rabbit = {
+ __proto__: animal,
+ eat: function() {
+ super.eat();
+ }
+};
+
+*!*
+rabbit.eat(); // Error calling super (because there's no [[HomeObject]])
+*/!*
+```
+
+## Summary
+
+1. To extend a class: `class Child extends Parent`:
+ - That means `Child.prototype.__proto__` will be `Parent.prototype`, so methods are inherited.
+2. When overriding a constructor:
+ - We must call parent constructor as `super()` in `Child` constructor before using `this`.
+3. When overriding another method:
+ - We can use `super.method()` in a `Child` method to call `Parent` method.
+4. Internals:
+ - Methods remember their class/object in the internal `[[HomeObject]]` property. That's how `super` resolves parent methods.
+ - So it's not safe to copy a method with `super` from one object to another.
+
+Also:
+- Arrow functions don't have their own `this` or `super`, so they transparently fit into the surrounding context.
diff --git a/1-js/09-classes/02-class-inheritance/class-inheritance-array-object.svg b/1-js/09-classes/02-class-inheritance/class-inheritance-array-object.svg
new file mode 100644
index 0000000000..5ea9bf29ea
--- /dev/null
+++ b/1-js/09-classes/02-class-inheritance/class-inheritance-array-object.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-animal-2.svg b/1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-animal-2.svg
new file mode 100644
index 0000000000..72e47e34c2
--- /dev/null
+++ b/1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-animal-2.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-animal.svg b/1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-animal.svg
new file mode 100644
index 0000000000..bced3d355e
--- /dev/null
+++ b/1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-animal.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/09-classes/02-class-inheritance/rabbit-animal-independent-animal.svg b/1-js/09-classes/02-class-inheritance/rabbit-animal-independent-animal.svg
new file mode 100644
index 0000000000..f53fc92dee
--- /dev/null
+++ b/1-js/09-classes/02-class-inheritance/rabbit-animal-independent-animal.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/09-classes/02-class-inheritance/rabbit-animal-independent-rabbit.svg b/1-js/09-classes/02-class-inheritance/rabbit-animal-independent-rabbit.svg
new file mode 100644
index 0000000000..2f30a3a901
--- /dev/null
+++ b/1-js/09-classes/02-class-inheritance/rabbit-animal-independent-rabbit.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/09-classes/02-class-inheritance/super-homeobject-wrong.svg b/1-js/09-classes/02-class-inheritance/super-homeobject-wrong.svg
new file mode 100644
index 0000000000..f6450ddc49
--- /dev/null
+++ b/1-js/09-classes/02-class-inheritance/super-homeobject-wrong.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/09-classes/02-class-inheritance/this-super-loop.svg b/1-js/09-classes/02-class-inheritance/this-super-loop.svg
new file mode 100644
index 0000000000..4f5f45034a
--- /dev/null
+++ b/1-js/09-classes/02-class-inheritance/this-super-loop.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/09-classes/02-class/1-rewrite-to-class/solution.view/index.html b/1-js/09-classes/02-class/1-rewrite-to-class/solution.view/index.html
deleted file mode 100644
index fdee13d01b..0000000000
--- a/1-js/09-classes/02-class/1-rewrite-to-class/solution.view/index.html
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
- Console clock
-
-
-
-
-
-
-
-
-
-
diff --git a/1-js/09-classes/02-class/1-rewrite-to-class/source.view/clock.js b/1-js/09-classes/02-class/1-rewrite-to-class/source.view/clock.js
deleted file mode 100644
index 537f7268c4..0000000000
--- a/1-js/09-classes/02-class/1-rewrite-to-class/source.view/clock.js
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-function Clock({ template }) {
- this.template = template;
-}
-
-Clock.prototype.render = function() {
- let date = new Date();
-
- let hours = date.getHours();
- if (hours < 10) hours = '0' + hours;
-
- let mins = date.getMinutes();
- if (mins < 10) mins = '0' + mins;
-
- let secs = date.getSeconds();
- if (secs < 10) secs = '0' + secs;
-
- let output = this.template
- .replace('h', hours)
- .replace('m', mins)
- .replace('s', secs);
-
- console.log(output);
-};
-
-Clock.prototype.stop = function() {
- clearInterval(this.timer);
-};
-
-Clock.prototype.start = function() {
- this.render();
- this.timer = setInterval(() => this.render(), 1000);
-};
diff --git a/1-js/09-classes/02-class/1-rewrite-to-class/source.view/index.html b/1-js/09-classes/02-class/1-rewrite-to-class/source.view/index.html
deleted file mode 100644
index fdee13d01b..0000000000
--- a/1-js/09-classes/02-class/1-rewrite-to-class/source.view/index.html
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
- Console clock
-
-
-
-
-
-
-
-
-
-
diff --git a/1-js/09-classes/02-class/1-rewrite-to-class/task.md b/1-js/09-classes/02-class/1-rewrite-to-class/task.md
deleted file mode 100644
index a29d347f52..0000000000
--- a/1-js/09-classes/02-class/1-rewrite-to-class/task.md
+++ /dev/null
@@ -1,9 +0,0 @@
-importance: 5
-
----
-
-# Rewrite to class
-
-Rewrite the `Clock` class from prototypes to the modern "class" syntax.
-
-P.S. The clock ticks in the console, open it to see.
diff --git a/1-js/09-classes/02-class/article.md b/1-js/09-classes/02-class/article.md
deleted file mode 100644
index dd9284ddd0..0000000000
--- a/1-js/09-classes/02-class/article.md
+++ /dev/null
@@ -1,272 +0,0 @@
-
-# Classes
-
-The "class" construct allows one to define prototype-based classes with a clean, nice-looking syntax. It also introduces great new features which are useful for object-oriented programming.
-
-## The "class" syntax
-
-The `class` syntax is versatile, we'll start with a simple example first.
-
-Here's a prototype-based class `User`:
-
-```js run
-function User(name) {
- this.name = name;
-}
-
-User.prototype.sayHi = function() {
- alert(this.name);
-}
-
-let user = new User("John");
-user.sayHi();
-```
-
-...And here's the same using `class` syntax:
-
-```js run
-class User {
-
- constructor(name) {
- this.name = name;
- }
-
- sayHi() {
- alert(this.name);
- }
-
-}
-
-let user = new User("John");
-user.sayHi();
-```
-
-It's easy to see that these two examples are alike. Be sure to note that methods in a class do not have a comma between them. A common pitfall for novice developers is to put a comma between class methods, which would result in a syntax error. The notation here is not to be confused with object literals. Within the class syntactical sugar, no commas are required.
-
-## What is a class?
-
-So, what exactly is a `class`? We may think that it defines a new language-level entity, but that would be wrong.
-
-In Javascript, a class is a kind of a function.
-
-The definition `class User {...}` creates a function under the same name and puts the methods into `User.prototype`. So the structure is similar.
-
-This is demonstrated in the following code, which you can run yourself:
-
-```js run
-class User {
- constructor(name) { this.name = name; }
- sayHi() { alert(this.name); }
-}
-
-*!*
-// proof: User is a function
-alert(typeof User); // function
-*/!*
-
-*!*
-// proof: User is the "constructor" function
-*/!*
-alert(User === User.prototype.constructor); // true
-
-*!*
-// proof: there are two methods in its "prototype"
-*/!*
-alert(Object.getOwnPropertyNames(User.prototype)); // constructor, sayHi
-```
-
-Abstractly, we can illustrate this process of `class User` creating a function as:
-
-
-
-`Class` is a special syntax to define a constructor together with its prototype methods. In addition to its basic operation, the `Class` syntax brings many other features with it which we'll explore later.
-
-## Class Expression
-
-Just like functions, classes can be defined inside another expression, passed around, returned etc.
-
-Here's a class-returning function - otherwise known as a "class factory":
-
-```js run
-function makeClass(phrase) {
-*!*
- // declare a class and return it
- return class {
- sayHi() {
- alert(phrase);
- };
- };
-*/!*
-}
-
-let User = makeClass("Hello");
-
-new User().sayHi(); // Hello
-```
-
-That's quite normal if we recall that `class` is just a special form of a function-with-prototype definition.
-
-And, like Named Function Expressions, such classes also may have a name, that is visible inside that class only:
-
-```js run
-// "Named Class Expression" (alas, no such term, but that's what's going on)
-let User = class *!*MyClass*/!* {
- sayHi() {
- alert(MyClass); // MyClass is visible only inside the class
- }
-};
-
-new User().sayHi(); // works, shows MyClass definition
-
-alert(MyClass); // error, MyClass not visible outside of the class
-```
-
-## Differences between classes and functions
-
-Classes have some differences compared to regular functions:
-
-Constructors require `new`
-: Unlike a regular function, a class `constructor` can't be called without `new`:
-
-```js run
-class User {
- constructor() {}
-}
-
-alert(typeof User); // function
-User(); // Error: Class constructor User cannot be invoked without 'new'
-```
-
-Different string output
-: If we output it like `alert(User)`, some engines show `"class User..."`, while others show `"function User..."`.
-
-Please don't be confused: the string representation may vary, but that's still a function, there is no separate "class" entity in JavaScript language.
-
-Class methods are non-enumerable
-: A class definition sets `enumerable` flag to `false` for all methods in the `"prototype"`. That's good, because if we `for..in` over an object, we usually don't want its class methods.
-
-Classes have a default `constructor() {}`
-: If there's no `constructor` in the `class` construct, then an empty function is generated, just as if we had written `constructor() {}`.
-
-Classes always `use strict`
-: All code inside the class construct is automatically in strict mode.
-
-
-## Getters/setters, other shorthands
-
-Classes also include getters/setters, generators, computed properties etc.
-
-Here's an example for `user.name` implemented using `get/set`:
-
-```js run
-class User {
-
- constructor(name) {
- // invokes the setter
- this.name = name;
- }
-
-*!*
- get name() {
-*/!*
- return this._name;
- }
-
-*!*
- set name(value) {
-*/!*
- if (value.length < 4) {
- alert("Name is too short.");
- return;
- }
- this._name = value;
- }
-
-}
-
-let user = new User("John");
-alert(user.name); // John
-
-user = new User(""); // Name too short.
-```
-
-Internally, getters and setters are created on `User.prototype`, like this:
-
-```js
-Object.defineProperties(User.prototype, {
- name: {
- get() {
- return this._name
- },
- set(name) {
- // ...
- }
- }
-});
-```
-
-Here's an example with computed properties:
-
-```js run
-function f() { return "sayHi"; }
-
-class User {
- [f()]() {
- alert("Hello");
- }
-
-}
-
-new User().sayHi();
-```
-
-For a generator method, similarly, prepend it with `*`.
-
-## Class properties
-
-```warn header="Old browsers may need a polyfill"
-Class-level properties are a recent addition to the language.
-```
-
-In the example above, `User` only had methods. Let's add a property:
-
-```js run
-class User {
- name = "Anonymous";
-
- sayHi() {
- alert(`Hello, ${this.name}!`);
- }
-}
-
-new User().sayHi();
-```
-
-The property is not placed into `User.prototype`. Instead, it is created by `new`, separately for every object. So, the property will never be shared between different objects of the same class.
-
-
-## Summary
-
-The basic class syntax looks like this:
-
-```js
-class MyClass {
- prop = value;
-
- constructor(...) {
- // ...
- }
-
- method(...) {}
-
- get something(...) {}
- set something(...) {}
-
- [Symbol.iterator]() {}
- // ...
-}
-```
-
-`MyClass` is technically a function, while methods are written to `MyClass.prototype`.
-
-In the next chapters we'll learn more about classes, including inheritance and other features.
diff --git a/1-js/09-classes/02-class/class-user.png b/1-js/09-classes/02-class/class-user.png
deleted file mode 100644
index f090909a20..0000000000
Binary files a/1-js/09-classes/02-class/class-user.png and /dev/null differ
diff --git a/1-js/09-classes/02-class/class-user@2x.png b/1-js/09-classes/02-class/class-user@2x.png
deleted file mode 100644
index b953f91e7e..0000000000
Binary files a/1-js/09-classes/02-class/class-user@2x.png and /dev/null differ
diff --git a/1-js/09-classes/03-class-inheritance/2-clock-class-extended/source.view/clock.js b/1-js/09-classes/03-class-inheritance/2-clock-class-extended/source.view/clock.js
deleted file mode 100644
index d701c0caeb..0000000000
--- a/1-js/09-classes/03-class-inheritance/2-clock-class-extended/source.view/clock.js
+++ /dev/null
@@ -1,34 +0,0 @@
-class Clock {
- constructor({ template }) {
- this.template = template;
- }
-
- render() {
- let date = new Date();
-
- let hours = date.getHours();
- if (hours < 10) hours = '0' + hours;
-
- let mins = date.getMinutes();
- if (mins < 10) mins = '0' + mins;
-
- let secs = date.getSeconds();
- if (secs < 10) secs = '0' + secs;
-
- let output = this.template
- .replace('h', hours)
- .replace('m', mins)
- .replace('s', secs);
-
- console.log(output);
- }
-
- stop() {
- clearInterval(this.timer);
- }
-
- start() {
- this.render();
- this.timer = setInterval(() => this.render(), 1000);
- }
-}
diff --git a/1-js/09-classes/03-class-inheritance/3-class-extend-object/rabbit-extends-object.png b/1-js/09-classes/03-class-inheritance/3-class-extend-object/rabbit-extends-object.png
deleted file mode 100644
index b0b1b6ad00..0000000000
Binary files a/1-js/09-classes/03-class-inheritance/3-class-extend-object/rabbit-extends-object.png and /dev/null differ
diff --git a/1-js/09-classes/03-class-inheritance/3-class-extend-object/rabbit-extends-object@2x.png b/1-js/09-classes/03-class-inheritance/3-class-extend-object/rabbit-extends-object@2x.png
deleted file mode 100644
index 76cd587700..0000000000
Binary files a/1-js/09-classes/03-class-inheritance/3-class-extend-object/rabbit-extends-object@2x.png and /dev/null differ
diff --git a/1-js/09-classes/03-class-inheritance/3-class-extend-object/solution.md b/1-js/09-classes/03-class-inheritance/3-class-extend-object/solution.md
deleted file mode 100644
index c1483aa365..0000000000
--- a/1-js/09-classes/03-class-inheritance/3-class-extend-object/solution.md
+++ /dev/null
@@ -1,81 +0,0 @@
-First, let's see why the latter code doesn't work.
-
-The reason becomes obvious if we try to run it. An inheriting class constructor must call `super()`. Otherwise `"this"` won't be "defined".
-
-So here's the fix:
-
-```js run
-class Rabbit extends Object {
- constructor(name) {
-*!*
- super(); // need to call the parent constructor when inheriting
-*/!*
- this.name = name;
- }
-}
-
-let rabbit = new Rabbit("Rab");
-
-alert( rabbit.hasOwnProperty('name') ); // true
-```
-
-But that's not all yet.
-
-Even after the fix, there's still important difference in `"class Rabbit extends Object"` versus `class Rabbit`.
-
-As we know, the "extends" syntax sets up two prototypes:
-
-1. Between `"prototype"` of the constructor functions (for methods).
-2. Between the constructor functions itself (for static methods).
-
-In our case, for `class Rabbit extends Object` it means:
-
-```js run
-class Rabbit extends Object {}
-
-alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) true
-alert( Rabbit.__proto__ === Object ); // (2) true
-```
-
-So `Rabbit` now provides access to static methods of `Object` via `Rabbit`, like this:
-
-```js run
-class Rabbit extends Object {}
-
-*!*
-// normally we call Object.getOwnPropertyNames
-alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // a,b
-*/!*
-```
-
-But if we don't have `extends Object`, then `Rabbit.__proto__` is not set to `Object`.
-
-Here's the demo:
-
-```js run
-class Rabbit {}
-
-alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) true
-alert( Rabbit.__proto__ === Object ); // (2) false (!)
-alert( Rabbit.__proto__ === Function.prototype ); // as any function by default
-
-*!*
-// error, no such function in Rabbit
-alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // Error
-*/!*
-```
-
-So `Rabbit` doesn't provide access to static methods of `Object` in that case.
-
-By the way, `Function.prototype` has "generic" function methods, like `call`, `bind` etc. They are ultimately available in both cases, because for the built-in `Object` constructor, `Object.__proto__ === Function.prototype`.
-
-Here's the picture:
-
-
-
-So, to put it short, there are two differences:
-
-| class Rabbit | class Rabbit extends Object |
-|--------------|------------------------------|
-| -- | needs to call `super()` in constructor |
-| `Rabbit.__proto__ === Function.prototype` | `Rabbit.__proto__ === Object` |
diff --git a/1-js/09-classes/03-class-inheritance/3-class-extend-object/task.md b/1-js/09-classes/03-class-inheritance/3-class-extend-object/task.md
deleted file mode 100644
index ca6628edf1..0000000000
--- a/1-js/09-classes/03-class-inheritance/3-class-extend-object/task.md
+++ /dev/null
@@ -1,43 +0,0 @@
-importance: 5
-
----
-
-# Class extends Object?
-
-As we know, all objects normally inherit from `Object.prototype` and get access to "generic" object methods like `hasOwnProperty` etc.
-
-For instance:
-
-```js run
-class Rabbit {
- constructor(name) {
- this.name = name;
- }
-}
-
-let rabbit = new Rabbit("Rab");
-
-*!*
-// hasOwnProperty method is from Object.prototype
-// rabbit.__proto__ === Object.prototype
-alert( rabbit.hasOwnProperty('name') ); // true
-*/!*
-```
-
-But if we spell it out explicitly like `"class Rabbit extends Object"`, then the result would be different from a simple `"class Rabbit"`?
-
-What's the difference?
-
-Here's an example of such code (it doesn't work -- why? fix it?):
-
-```js
-class Rabbit extends Object {
- constructor(name) {
- this.name = name;
- }
-}
-
-let rabbit = new Rabbit("Rab");
-
-alert( rabbit.hasOwnProperty('name') ); // true
-```
diff --git a/1-js/09-classes/03-class-inheritance/animal-rabbit-extends.png b/1-js/09-classes/03-class-inheritance/animal-rabbit-extends.png
deleted file mode 100644
index ffdb6df784..0000000000
Binary files a/1-js/09-classes/03-class-inheritance/animal-rabbit-extends.png and /dev/null differ
diff --git a/1-js/09-classes/03-class-inheritance/animal-rabbit-extends@2x.png b/1-js/09-classes/03-class-inheritance/animal-rabbit-extends@2x.png
deleted file mode 100644
index e532c1823a..0000000000
Binary files a/1-js/09-classes/03-class-inheritance/animal-rabbit-extends@2x.png and /dev/null differ
diff --git a/1-js/09-classes/03-class-inheritance/article.md b/1-js/09-classes/03-class-inheritance/article.md
deleted file mode 100644
index 1541a9650a..0000000000
--- a/1-js/09-classes/03-class-inheritance/article.md
+++ /dev/null
@@ -1,431 +0,0 @@
-
-# Class inheritance
-
-Classes can extend one another. There's a nice syntax, technically based on the prototypal inheritance.
-
-To inherit from another class, we should specify `"extends"` and the parent class before the brackets `{..}`.
-
-Here `Rabbit` inherits from `Animal`:
-
-```js run
-class Animal {
-
- constructor(name) {
- this.speed = 0;
- this.name = name;
- }
-
- run(speed) {
- this.speed += speed;
- alert(`${this.name} runs with speed ${this.speed}.`);
- }
-
- stop() {
- this.speed = 0;
- alert(`${this.name} stopped.`);
- }
-
-}
-
-*!*
-// Inherit from Animal
-class Rabbit extends Animal {
- hide() {
- alert(`${this.name} hides!`);
- }
-}
-*/!*
-
-let rabbit = new Rabbit("White Rabbit");
-
-rabbit.run(5); // White Rabbit runs with speed 5.
-rabbit.hide(); // White Rabbit hides!
-```
-
-The `extends` keyword actually adds a `[[Prototype]]` reference from `Rabbit.prototype` to `Animal.prototype`, just as you expect it to be, and as we've seen before.
-
-
-
-So now `rabbit` has access both to its own methods and to methods of `Animal`.
-
-````smart header="Any expression is allowed after `extends`"
-Class syntax allows to specify not just a class, but any expression after `extends`.
-
-For instance, a function call that generates the parent class:
-
-```js run
-function f(phrase) {
- return class {
- sayHi() { alert(phrase) }
- }
-}
-
-*!*
-class User extends f("Hello") {}
-*/!*
-
-new User().sayHi(); // Hello
-```
-Here `class User` inherits from the result of `f("Hello")`.
-
-That may be useful for advanced programming patterns when we use functions to generate classes depending on many conditions and can inherit from them.
-````
-
-## Overriding a method
-
-Now let's move forward and override a method. As of now, `Rabbit` inherits the `stop` method that sets `this.speed = 0` from `Animal`.
-
-If we specify our own `stop` in `Rabbit`, then it will be used instead:
-
-```js
-class Rabbit extends Animal {
- stop() {
- // ...this will be used for rabbit.stop()
- }
-}
-```
-
-
-...But usually we don't want to totally replace a parent method, but rather to build on top of it, tweak or extend its functionality. We do something in our method, but call the parent method before/after it or in the process.
-
-Classes provide `"super"` keyword for that.
-
-- `super.method(...)` to call a parent method.
-- `super(...)` to call a parent constructor (inside our constructor only).
-
-For instance, let our rabbit autohide when stopped:
-
-```js run
-class Animal {
-
- constructor(name) {
- this.speed = 0;
- this.name = name;
- }
-
- run(speed) {
- this.speed += speed;
- alert(`${this.name} runs with speed ${this.speed}.`);
- }
-
- stop() {
- this.speed = 0;
- alert(`${this.name} stopped.`);
- }
-
-}
-
-class Rabbit extends Animal {
- hide() {
- alert(`${this.name} hides!`);
- }
-
-*!*
- stop() {
- super.stop(); // call parent stop
- this.hide(); // and then hide
- }
-*/!*
-}
-
-let rabbit = new Rabbit("White Rabbit");
-
-rabbit.run(5); // White Rabbit runs with speed 5.
-rabbit.stop(); // White Rabbit stopped. White rabbit hides!
-```
-
-Now `Rabbit` has the `stop` method that calls the parent `super.stop()` in the process.
-
-````smart header="Arrow functions have no `super`"
-As was mentioned in the chapter , arrow functions do not have `super`.
-
-If accessed, it's taken from the outer function. For instance:
-```js
-class Rabbit extends Animal {
- stop() {
- setTimeout(() => super.stop(), 1000); // call parent stop after 1sec
- }
-}
-```
-
-The `super` in the arrow function is the same as in `stop()`, so it works as intended. If we specified a "regular" function here, there would be an error:
-
-```js
-// Unexpected super
-setTimeout(function() { super.stop() }, 1000);
-```
-````
-
-
-## Overriding constructor
-
-With constructors it gets a little bit tricky.
-
-Till now, `Rabbit` did not have its own `constructor`.
-
-According to the [specification](https://tc39.github.io/ecma262/#sec-runtime-semantics-classdefinitionevaluation), if a class extends another class and has no `constructor`, then the following `constructor` is generated:
-
-```js
-class Rabbit extends Animal {
- // generated for extending classes without own constructors
-*!*
- constructor(...args) {
- super(...args);
- }
-*/!*
-}
-```
-
-As we can see, it basically calls the parent `constructor` passing it all the arguments. That happens if we don't write a constructor of our own.
-
-Now let's add a custom constructor to `Rabbit`. It will specify the `earLength` in addition to `name`:
-
-```js run
-class Animal {
- constructor(name) {
- this.speed = 0;
- this.name = name;
- }
- // ...
-}
-
-class Rabbit extends Animal {
-
-*!*
- constructor(name, earLength) {
- this.speed = 0;
- this.name = name;
- this.earLength = earLength;
- }
-*/!*
-
- // ...
-}
-
-*!*
-// Doesn't work!
-let rabbit = new Rabbit("White Rabbit", 10); // Error: this is not defined.
-*/!*
-```
-
-Whoops! We've got an error. Now we can't create rabbits. What went wrong?
-
-The short answer is: constructors in inheriting classes must call `super(...)`, and (!) do it before using `this`.
-
-...But why? What's going on here? Indeed, the requirement seems strange.
-
-Of course, there's an explanation. Let's get into details, so you'd really understand what's going on.
-
-In JavaScript, there's a distinction between a "constructor function of an inheriting class" and all others. In an inheriting class, the corresponding constructor function is labelled with a special internal property `[[ConstructorKind]]:"derived"`.
-
-The difference is:
-
-- When a normal constructor runs, it creates an empty object as `this` and continues with it.
-- But when a derived constructor runs, it doesn't do it. It expects the parent constructor to do this job.
-
-So if we're making a constructor of our own, then we must call `super`, because otherwise the object with `this` reference to it won't be created. And we'll get an error.
-
-For `Rabbit` to work, we need to call `super()` before using `this`, like here:
-
-```js run
-class Animal {
-
- constructor(name) {
- this.speed = 0;
- this.name = name;
- }
-
- // ...
-}
-
-class Rabbit extends Animal {
-
- constructor(name, earLength) {
-*!*
- super(name);
-*/!*
- this.earLength = earLength;
- }
-
- // ...
-}
-
-*!*
-// now fine
-let rabbit = new Rabbit("White Rabbit", 10);
-alert(rabbit.name); // White Rabbit
-alert(rabbit.earLength); // 10
-*/!*
-```
-
-
-## Super: internals, [[HomeObject]]
-
-Let's get a little deeper under the hood of `super`. We'll see some interesting things by the way.
-
-First to say, from all that we've learned till now, it's impossible for `super` to work.
-
-Yeah, indeed, let's ask ourselves, how it could technically work? When an object method runs, it gets the current object as `this`. If we call `super.method()` then, how to retrieve the `method`? Naturally, we need to take the `method` from the prototype of the current object. How, technically, we (or a JavaScript engine) can do it?
-
-Maybe we can get the method from `[[Prototype]]` of `this`, as `this.__proto__.method`? Unfortunately, that doesn't work.
-
-Let's try to do it. Without classes, using plain objects for the sake of simplicity.
-
-Here, `rabbit.eat()` should call `animal.eat()` method of the parent object:
-
-```js run
-let animal = {
- name: "Animal",
- eat() {
- alert(`${this.name} eats.`);
- }
-};
-
-let rabbit = {
- __proto__: animal,
- name: "Rabbit",
- eat() {
-*!*
- // that's how super.eat() could presumably work
- this.__proto__.eat.call(this); // (*)
-*/!*
- }
-};
-
-rabbit.eat(); // Rabbit eats.
-```
-
-At the line `(*)` we take `eat` from the prototype (`animal`) and call it in the context of the current object. Please note that `.call(this)` is important here, because a simple `this.__proto__.eat()` would execute parent `eat` in the context of the prototype, not the current object.
-
-And in the code above it actually works as intended: we have the correct `alert`.
-
-Now let's add one more object to the chain. We'll see how things break:
-
-```js run
-let animal = {
- name: "Animal",
- eat() {
- alert(`${this.name} eats.`);
- }
-};
-
-let rabbit = {
- __proto__: animal,
- eat() {
- // ...bounce around rabbit-style and call parent (animal) method
- this.__proto__.eat.call(this); // (*)
- }
-};
-
-let longEar = {
- __proto__: rabbit,
- eat() {
- // ...do something with long ears and call parent (rabbit) method
- this.__proto__.eat.call(this); // (**)
- }
-};
-
-*!*
-longEar.eat(); // Error: Maximum call stack size exceeded
-*/!*
-```
-
-The code doesn't work anymore! We can see the error trying to call `longEar.eat()`.
-
-It may be not that obvious, but if we trace `longEar.eat()` call, then we can see why. In both lines `(*)` and `(**)` the value of `this` is the current object (`longEar`). That's essential: all object methods get the current object as `this`, not a prototype or something.
-
-So, in both lines `(*)` and `(**)` the value of `this.__proto__` is exactly the same: `rabbit`. They both call `rabbit.eat` without going up the chain in the endless loop.
-
-Here's the picture of what happens:
-
-
-
-1. Inside `longEar.eat()`, the line `(**)` calls `rabbit.eat` providing it with `this=longEar`.
- ```js
- // inside longEar.eat() we have this = longEar
- this.__proto__.eat.call(this) // (**)
- // becomes
- longEar.__proto__.eat.call(this)
- // that is
- rabbit.eat.call(this);
- ```
-2. Then in the line `(*)` of `rabbit.eat`, we'd like to pass the call even higher in the chain, but `this=longEar`, so `this.__proto__.eat` is again `rabbit.eat`!
-
- ```js
- // inside rabbit.eat() we also have this = longEar
- this.__proto__.eat.call(this) // (*)
- // becomes
- longEar.__proto__.eat.call(this)
- // or (again)
- rabbit.eat.call(this);
- ```
-
-3. ...So `rabbit.eat` calls itself in the endless loop, because it can't ascend any further.
-
-The problem can't be solved by using `this` alone.
-
-### `[[HomeObject]]`
-
-To provide the solution, JavaScript adds one more special internal property for functions: `[[HomeObject]]`.
-
-**When a function is specified as a class or object method, its `[[HomeObject]]` property becomes that object.**
-
-This actually violates the idea of "unbound" functions, because methods remember their objects. And `[[HomeObject]]` can't be changed, so this bound is forever. So that's a very important change in the language.
-
-But this change is safe. `[[HomeObject]]` is used only for calling parent methods in `super`, to resolve the prototype. So it doesn't break compatibility.
-
-Let's see how it works for `super` -- again, using plain objects:
-
-```js run
-let animal = {
- name: "Animal",
- eat() { // [[HomeObject]] == animal
- alert(`${this.name} eats.`);
- }
-};
-
-let rabbit = {
- __proto__: animal,
- name: "Rabbit",
- eat() { // [[HomeObject]] == rabbit
- super.eat();
- }
-};
-
-let longEar = {
- __proto__: rabbit,
- name: "Long Ear",
- eat() { // [[HomeObject]] == longEar
- super.eat();
- }
-};
-
-*!*
-longEar.eat(); // Long Ear eats.
-*/!*
-```
-
-Every method remembers its object in the internal `[[HomeObject]]` property. Then `super` uses it to resolve the parent prototype.
-
-`[[HomeObject]]` is defined for methods defined both in classes and in plain objects. But for objects, methods must be specified exactly the given way: as `method()`, not as `"method: function()"`.
-
-In the example below a non-method syntax is used for comparison. `[[HomeObject]]` property is not set and the inheritance doesn't work:
-
-```js run
-let animal = {
- eat: function() { // should be the short syntax: eat() {...}
- // ...
- }
-};
-
-let rabbit = {
- __proto__: animal,
- eat: function() {
- super.eat();
- }
-};
-
-*!*
-rabbit.eat(); // Error calling super (because there's no [[HomeObject]])
-*/!*
-```
diff --git a/1-js/09-classes/03-class-inheritance/class-inheritance-array-object.png b/1-js/09-classes/03-class-inheritance/class-inheritance-array-object.png
deleted file mode 100644
index 4bb5bb95ec..0000000000
Binary files a/1-js/09-classes/03-class-inheritance/class-inheritance-array-object.png and /dev/null differ
diff --git a/1-js/09-classes/03-class-inheritance/class-inheritance-array-object@2x.png b/1-js/09-classes/03-class-inheritance/class-inheritance-array-object@2x.png
deleted file mode 100644
index 4741353f7f..0000000000
Binary files a/1-js/09-classes/03-class-inheritance/class-inheritance-array-object@2x.png and /dev/null differ
diff --git a/1-js/09-classes/03-class-inheritance/class-inheritance-rabbit-animal.png b/1-js/09-classes/03-class-inheritance/class-inheritance-rabbit-animal.png
deleted file mode 100644
index 0da6479d76..0000000000
Binary files a/1-js/09-classes/03-class-inheritance/class-inheritance-rabbit-animal.png and /dev/null differ
diff --git a/1-js/09-classes/03-class-inheritance/class-inheritance-rabbit-animal@2x.png b/1-js/09-classes/03-class-inheritance/class-inheritance-rabbit-animal@2x.png
deleted file mode 100644
index ebe8c0325c..0000000000
Binary files a/1-js/09-classes/03-class-inheritance/class-inheritance-rabbit-animal@2x.png and /dev/null differ
diff --git a/1-js/09-classes/03-class-inheritance/class-inheritance-rabbit-run-animal.png b/1-js/09-classes/03-class-inheritance/class-inheritance-rabbit-run-animal.png
deleted file mode 100644
index 387975a9c7..0000000000
Binary files a/1-js/09-classes/03-class-inheritance/class-inheritance-rabbit-run-animal.png and /dev/null differ
diff --git a/1-js/09-classes/03-class-inheritance/class-inheritance-rabbit-run-animal@2x.png b/1-js/09-classes/03-class-inheritance/class-inheritance-rabbit-run-animal@2x.png
deleted file mode 100644
index ca73135933..0000000000
Binary files a/1-js/09-classes/03-class-inheritance/class-inheritance-rabbit-run-animal@2x.png and /dev/null differ
diff --git a/1-js/09-classes/03-class-inheritance/this-super-loop.png b/1-js/09-classes/03-class-inheritance/this-super-loop.png
deleted file mode 100644
index 74d1d88e11..0000000000
Binary files a/1-js/09-classes/03-class-inheritance/this-super-loop.png and /dev/null differ
diff --git a/1-js/09-classes/03-class-inheritance/this-super-loop@2x.png b/1-js/09-classes/03-class-inheritance/this-super-loop@2x.png
deleted file mode 100644
index 8ce876f1ab..0000000000
Binary files a/1-js/09-classes/03-class-inheritance/this-super-loop@2x.png and /dev/null differ
diff --git a/1-js/09-classes/03-static-properties-methods/3-class-extend-object/rabbit-extends-object.svg b/1-js/09-classes/03-static-properties-methods/3-class-extend-object/rabbit-extends-object.svg
new file mode 100644
index 0000000000..915ab9aa64
--- /dev/null
+++ b/1-js/09-classes/03-static-properties-methods/3-class-extend-object/rabbit-extends-object.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/09-classes/03-static-properties-methods/3-class-extend-object/solution.md b/1-js/09-classes/03-static-properties-methods/3-class-extend-object/solution.md
new file mode 100644
index 0000000000..cb9829ce05
--- /dev/null
+++ b/1-js/09-classes/03-static-properties-methods/3-class-extend-object/solution.md
@@ -0,0 +1,81 @@
+First, let's see why the latter code doesn't work.
+
+The reason becomes obvious if we try to run it. An inheriting class constructor must call `super()`. Otherwise `"this"` won't be "defined".
+
+So here's the fix:
+
+```js run
+class Rabbit extends Object {
+ constructor(name) {
+*!*
+ super(); // need to call the parent constructor when inheriting
+*/!*
+ this.name = name;
+ }
+}
+
+let rabbit = new Rabbit("Rab");
+
+alert( rabbit.hasOwnProperty('name') ); // true
+```
+
+But that's not all yet.
+
+Even after the fix, there's still an important difference between `"class Rabbit extends Object"` and `class Rabbit`.
+
+As we know, the "extends" syntax sets up two prototypes:
+
+1. Between `"prototype"` of the constructor functions (for methods).
+2. Between the constructor functions themselves (for static methods).
+
+In the case of `class Rabbit extends Object` it means:
+
+```js run
+class Rabbit extends Object {}
+
+alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) true
+alert( Rabbit.__proto__ === Object ); // (2) true
+```
+
+So `Rabbit` now provides access to the static methods of `Object` via `Rabbit`, like this:
+
+```js run
+class Rabbit extends Object {}
+
+*!*
+// normally we call Object.getOwnPropertyNames
+alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // a,b
+*/!*
+```
+
+But if we don't have `extends Object`, then `Rabbit.__proto__` is not set to `Object`.
+
+Here's the demo:
+
+```js run
+class Rabbit {}
+
+alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) true
+alert( Rabbit.__proto__ === Object ); // (2) false (!)
+alert( Rabbit.__proto__ === Function.prototype ); // as any function by default
+
+*!*
+// error, no such function in Rabbit
+alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // Error
+*/!*
+```
+
+So `Rabbit` doesn't provide access to static methods of `Object` in that case.
+
+By the way, `Function.prototype` also has "generic" function methods, like `call`, `bind` etc. They are ultimately available in both cases, because for the built-in `Object` constructor, `Object.__proto__ === Function.prototype`.
+
+Here's the picture:
+
+
+
+So, to put it short, there are two differences:
+
+| class Rabbit | class Rabbit extends Object |
+|--------------|------------------------------|
+| -- | needs to call `super()` in constructor |
+| `Rabbit.__proto__ === Function.prototype` | `Rabbit.__proto__ === Object` |
diff --git a/1-js/09-classes/03-static-properties-methods/3-class-extend-object/task.md b/1-js/09-classes/03-static-properties-methods/3-class-extend-object/task.md
new file mode 100644
index 0000000000..1d0f98a74e
--- /dev/null
+++ b/1-js/09-classes/03-static-properties-methods/3-class-extend-object/task.md
@@ -0,0 +1,42 @@
+importance: 3
+
+---
+
+# Class extends Object?
+
+As we know, all objects normally inherit from `Object.prototype` and get access to "generic" object methods like `hasOwnProperty` etc.
+
+For instance:
+
+```js run
+class Rabbit {
+ constructor(name) {
+ this.name = name;
+ }
+}
+
+let rabbit = new Rabbit("Rab");
+
+*!*
+// hasOwnProperty method is from Object.prototype
+alert( rabbit.hasOwnProperty('name') ); // true
+*/!*
+```
+
+But if we spell it out explicitly like `"class Rabbit extends Object"`, then the result would be different from a simple `"class Rabbit"`?
+
+What's the difference?
+
+Here's an example of such code (it doesn't work -- why? fix it?):
+
+```js
+class Rabbit extends Object {
+ constructor(name) {
+ this.name = name;
+ }
+}
+
+let rabbit = new Rabbit("Rab");
+
+alert( rabbit.hasOwnProperty('name') ); // Error
+```
diff --git a/1-js/09-classes/03-static-properties-methods/animal-rabbit-static.svg b/1-js/09-classes/03-static-properties-methods/animal-rabbit-static.svg
new file mode 100644
index 0000000000..3e354b895d
--- /dev/null
+++ b/1-js/09-classes/03-static-properties-methods/animal-rabbit-static.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/09-classes/03-static-properties-methods/article.md b/1-js/09-classes/03-static-properties-methods/article.md
new file mode 100644
index 0000000000..4b493a5e8b
--- /dev/null
+++ b/1-js/09-classes/03-static-properties-methods/article.md
@@ -0,0 +1,249 @@
+
+# Static properties and methods
+
+We can also assign a method to the class as a whole. Such methods are called *static*.
+
+In a class declaration, they are prepended by `static` keyword, like this:
+
+```js run
+class User {
+*!*
+ static staticMethod() {
+*/!*
+ alert(this === User);
+ }
+}
+
+User.staticMethod(); // true
+```
+
+That actually does the same as assigning it as a property directly:
+
+```js run
+class User { }
+
+User.staticMethod = function() {
+ alert(this === User);
+};
+
+User.staticMethod(); // true
+```
+
+The value of `this` in `User.staticMethod()` call is the class constructor `User` itself (the "object before dot" rule).
+
+Usually, static methods are used to implement functions that belong to the class as a whole, but not to any particular object of it.
+
+For instance, we have `Article` objects and need a function to compare them.
+
+A natural solution would be to add `Article.compare` static method:
+
+```js run
+class Article {
+ constructor(title, date) {
+ this.title = title;
+ this.date = date;
+ }
+
+*!*
+ static compare(articleA, articleB) {
+ return articleA.date - articleB.date;
+ }
+*/!*
+}
+
+// usage
+let articles = [
+ new Article("HTML", new Date(2019, 1, 1)),
+ new Article("CSS", new Date(2019, 0, 1)),
+ new Article("JavaScript", new Date(2019, 11, 1))
+];
+
+*!*
+articles.sort(Article.compare);
+*/!*
+
+alert( articles[0].title ); // CSS
+```
+
+Here `Article.compare` method stands "above" articles, as a means to compare them. It's not a method of an article, but rather of the whole class.
+
+Another example would be a so-called "factory" method.
+
+Let's say, we need multiple ways to create an article:
+
+1. Create by given parameters (`title`, `date` etc).
+2. Create an empty article with today's date.
+3. ...or else somehow.
+
+The first way can be implemented by the constructor. And for the second one we can make a static method of the class.
+
+Such as `Article.createTodays()` here:
+
+```js run
+class Article {
+ constructor(title, date) {
+ this.title = title;
+ this.date = date;
+ }
+
+*!*
+ static createTodays() {
+ // remember, this = Article
+ return new this("Today's digest", new Date());
+ }
+*/!*
+}
+
+let article = Article.createTodays();
+
+alert( article.title ); // Today's digest
+```
+
+Now every time we need to create a today's digest, we can call `Article.createTodays()`. Once again, that's not a method of an article, but a method of the whole class.
+
+Static methods are also used in database-related classes to search/save/remove entries from the database, like this:
+
+```js
+// assuming Article is a special class for managing articles
+// static method to remove the article by id:
+Article.remove({id: 12345});
+```
+
+````warn header="Static methods aren't available for individual objects"
+Static methods are callable on classes, not on individual objects.
+
+E.g. such code won't work:
+
+```js
+// ...
+article.createTodays(); /// Error: article.createTodays is not a function
+```
+````
+
+## Static properties
+
+[recent browser=Chrome]
+
+Static properties are also possible, they look like regular class properties, but prepended by `static`:
+
+```js run
+class Article {
+ static publisher = "Ilya Kantor";
+}
+
+alert( Article.publisher ); // Ilya Kantor
+```
+
+That is the same as a direct assignment to `Article`:
+
+```js
+Article.publisher = "Ilya Kantor";
+```
+
+## Inheritance of static properties and methods [#statics-and-inheritance]
+
+Static properties and methods are inherited.
+
+For instance, `Animal.compare` and `Animal.planet` in the code below are inherited and accessible as `Rabbit.compare` and `Rabbit.planet`:
+
+```js run
+class Animal {
+ static planet = "Earth";
+
+ constructor(name, speed) {
+ this.speed = speed;
+ this.name = name;
+ }
+
+ run(speed = 0) {
+ this.speed += speed;
+ alert(`${this.name} runs with speed ${this.speed}.`);
+ }
+
+*!*
+ static compare(animalA, animalB) {
+ return animalA.speed - animalB.speed;
+ }
+*/!*
+
+}
+
+// Inherit from Animal
+class Rabbit extends Animal {
+ hide() {
+ alert(`${this.name} hides!`);
+ }
+}
+
+let rabbits = [
+ new Rabbit("White Rabbit", 10),
+ new Rabbit("Black Rabbit", 5)
+];
+
+*!*
+rabbits.sort(Rabbit.compare);
+*/!*
+
+rabbits[0].run(); // Black Rabbit runs with speed 5.
+
+alert(Rabbit.planet); // Earth
+```
+
+Now when we call `Rabbit.compare`, the inherited `Animal.compare` will be called.
+
+How does it work? Again, using prototypes. As you might have already guessed, `extends` gives `Rabbit` the `[[Prototype]]` reference to `Animal`.
+
+
+
+So, `Rabbit extends Animal` creates two `[[Prototype]]` references:
+
+1. `Rabbit` function prototypally inherits from `Animal` function.
+2. `Rabbit.prototype` prototypally inherits from `Animal.prototype`.
+
+As a result, inheritance works both for regular and static methods.
+
+Here, let's check that by code:
+
+```js run
+class Animal {}
+class Rabbit extends Animal {}
+
+// for statics
+alert(Rabbit.__proto__ === Animal); // true
+
+// for regular methods
+alert(Rabbit.prototype.__proto__ === Animal.prototype); // true
+```
+
+## Summary
+
+Static methods are used for the functionality that belongs to the class "as a whole". It doesn't relate to a concrete class instance.
+
+For example, a method for comparison `Article.compare(article1, article2)` or a factory method `Article.createTodays()`.
+
+They are labeled by the word `static` in class declaration.
+
+Static properties are used when we'd like to store class-level data, also not bound to an instance.
+
+The syntax is:
+
+```js
+class MyClass {
+ static property = ...;
+
+ static method() {
+ ...
+ }
+}
+```
+
+Technically, static declaration is the same as assigning to the class itself:
+
+```js
+MyClass.property = ...
+MyClass.method = ...
+```
+
+Static properties and methods are inherited.
+
+For `class B extends A` the prototype of the class `B` itself points to `A`: `B.[[Prototype]] = A`. So if a field is not found in `B`, the search continues in `A`.
diff --git a/1-js/09-classes/04-private-protected-properties-methods/article.md b/1-js/09-classes/04-private-protected-properties-methods/article.md
new file mode 100644
index 0000000000..91efb89eeb
--- /dev/null
+++ b/1-js/09-classes/04-private-protected-properties-methods/article.md
@@ -0,0 +1,322 @@
+
+# Private and protected properties and methods
+
+One of the most important principles of object oriented programming -- delimiting internal interface from the external one.
+
+That is "a must" practice in developing anything more complex than a "hello world" app.
+
+To understand this, let's break away from development and turn our eyes into the real world.
+
+Usually, devices that we're using are quite complex. But delimiting the internal interface from the external one allows to use them without problems.
+
+## A real-life example
+
+For instance, a coffee machine. Simple from outside: a button, a display, a few holes...And, surely, the result -- great coffee! :)
+
+
+
+But inside... (a picture from the repair manual)
+
+
+
+A lot of details. But we can use it without knowing anything.
+
+Coffee machines are quite reliable, aren't they? We can use one for years, and only if something goes wrong -- bring it for repairs.
+
+The secret of reliability and simplicity of a coffee machine -- all details are well-tuned and *hidden* inside.
+
+If we remove the protective cover from the coffee machine, then using it will be much more complex (where to press?), and dangerous (it can electrocute).
+
+As we'll see, in programming objects are like coffee machines.
+
+But in order to hide inner details, we'll use not a protective cover, but rather special syntax of the language and conventions.
+
+## Internal and external interface
+
+In object-oriented programming, properties and methods are split into two groups:
+
+- *Internal interface* -- methods and properties, accessible from other methods of the class, but not from the outside.
+- *External interface* -- methods and properties, accessible also from outside the class.
+
+If we continue the analogy with the coffee machine -- what's hidden inside: a boiler tube, heating element, and so on -- is its internal interface.
+
+An internal interface is used for the object to work, its details use each other. For instance, a boiler tube is attached to the heating element.
+
+But from the outside a coffee machine is closed by the protective cover, so that no one can reach those. Details are hidden and inaccessible. We can use its features via the external interface.
+
+So, all we need to use an object is to know its external interface. We may be completely unaware how it works inside, and that's great.
+
+That was a general introduction.
+
+In JavaScript, there are two types of object fields (properties and methods):
+
+- Public: accessible from anywhere. They comprise the external interface. Until now we were only using public properties and methods.
+- Private: accessible only from inside the class. These are for the internal interface.
+
+In many other languages there also exist "protected" fields: accessible only from inside the class and those extending it (like private, but plus access from inheriting classes). They are also useful for the internal interface. They are in a sense more widespread than private ones, because we usually want inheriting classes to gain access to them.
+
+Protected fields are not implemented in JavaScript on the language level, but in practice they are very convenient, so they are emulated.
+
+Now we'll make a coffee machine in JavaScript with all these types of properties. A coffee machine has a lot of details, we won't model them to stay simple (though we could).
+
+## Protecting "waterAmount"
+
+Let's make a simple coffee machine class first:
+
+```js run
+class CoffeeMachine {
+ waterAmount = 0; // the amount of water inside
+
+ constructor(power) {
+ this.power = power;
+ alert( `Created a coffee-machine, power: ${power}` );
+ }
+
+}
+
+// create the coffee machine
+let coffeeMachine = new CoffeeMachine(100);
+
+// add water
+coffeeMachine.waterAmount = 200;
+```
+
+Right now the properties `waterAmount` and `power` are public. We can easily get/set them from the outside to any value.
+
+Let's change `waterAmount` property to protected to have more control over it. For instance, we don't want anyone to set it below zero.
+
+**Protected properties are usually prefixed with an underscore `_`.**
+
+That is not enforced on the language level, but there's a well-known convention between programmers that such properties and methods should not be accessed from the outside.
+
+So our property will be called `_waterAmount`:
+
+```js run
+class CoffeeMachine {
+ _waterAmount = 0;
+
+ set waterAmount(value) {
+ if (value < 0) {
+ value = 0;
+ }
+ this._waterAmount = value;
+ }
+
+ get waterAmount() {
+ return this._waterAmount;
+ }
+
+ constructor(power) {
+ this._power = power;
+ }
+
+}
+
+// create the coffee machine
+let coffeeMachine = new CoffeeMachine(100);
+
+// add water
+coffeeMachine.waterAmount = -10; // _waterAmount will become 0, not -10
+```
+
+Now the access is under control, so setting the water amount below zero becomes impossible.
+
+## Read-only "power"
+
+For `power` property, let's make it read-only. It sometimes happens that a property must be set at creation time only, and then never modified.
+
+That's exactly the case for a coffee machine: power never changes.
+
+To do so, we only need to make getter, but not the setter:
+
+```js run
+class CoffeeMachine {
+ // ...
+
+ constructor(power) {
+ this._power = power;
+ }
+
+ get power() {
+ return this._power;
+ }
+
+}
+
+// create the coffee machine
+let coffeeMachine = new CoffeeMachine(100);
+
+alert(`Power is: ${coffeeMachine.power}W`); // Power is: 100W
+
+coffeeMachine.power = 25; // Error (no setter)
+```
+
+````smart header="Getter/setter functions"
+Here we used getter/setter syntax.
+
+But most of the time `get.../set...` functions are preferred, like this:
+
+```js
+class CoffeeMachine {
+ _waterAmount = 0;
+
+ *!*setWaterAmount(value)*/!* {
+ if (value < 0) value = 0;
+ this._waterAmount = value;
+ }
+
+ *!*getWaterAmount()*/!* {
+ return this._waterAmount;
+ }
+}
+
+new CoffeeMachine().setWaterAmount(100);
+```
+
+That looks a bit longer, but functions are more flexible. They can accept multiple arguments (even if we don't need them right now).
+
+On the other hand, get/set syntax is shorter, so ultimately there's no strict rule, it's up to you to decide.
+````
+
+```smart header="Protected fields are inherited"
+If we inherit `class MegaMachine extends CoffeeMachine`, then nothing prevents us from accessing `this._waterAmount` or `this._power` from the methods of the new class.
+
+So protected fields are naturally inheritable. Unlike private ones that we'll see below.
+```
+
+## Private "#waterLimit"
+
+[recent browser=none]
+
+There's a finished JavaScript proposal, almost in the standard, that provides language-level support for private properties and methods.
+
+Privates should start with `#`. They are only accessible from inside the class.
+
+For instance, here's a private `#waterLimit` property and the water-checking private method `#fixWaterAmount`:
+
+```js run
+class CoffeeMachine {
+*!*
+ #waterLimit = 200;
+*/!*
+
+*!*
+ #fixWaterAmount(value) {
+ if (value < 0) return 0;
+ if (value > this.#waterLimit) return this.#waterLimit;
+ }
+*/!*
+
+ setWaterAmount(value) {
+ this.#waterLimit = this.#fixWaterAmount(value);
+ }
+
+}
+
+let coffeeMachine = new CoffeeMachine();
+
+*!*
+// can't access privates from outside of the class
+coffeeMachine.#fixWaterAmount(123); // Error
+coffeeMachine.#waterLimit = 1000; // Error
+*/!*
+```
+
+On the language level, `#` is a special sign that the field is private. We can't access it from outside or from inheriting classes.
+
+Private fields do not conflict with public ones. We can have both private `#waterAmount` and public `waterAmount` fields at the same time.
+
+For instance, let's make `waterAmount` an accessor for `#waterAmount`:
+
+```js run
+class CoffeeMachine {
+
+ #waterAmount = 0;
+
+ get waterAmount() {
+ return this.#waterAmount;
+ }
+
+ set waterAmount(value) {
+ if (value < 0) value = 0;
+ this.#waterAmount = value;
+ }
+}
+
+let machine = new CoffeeMachine();
+
+machine.waterAmount = 100;
+alert(machine.#waterAmount); // Error
+```
+
+Unlike protected ones, private fields are enforced by the language itself. That's a good thing.
+
+But if we inherit from `CoffeeMachine`, then we'll have no direct access to `#waterAmount`. We'll need to rely on `waterAmount` getter/setter:
+
+```js
+class MegaCoffeeMachine extends CoffeeMachine {
+ method() {
+*!*
+ alert( this.#waterAmount ); // Error: can only access from CoffeeMachine
+*/!*
+ }
+}
+```
+
+In many scenarios such limitation is too severe. If we extend a `CoffeeMachine`, we may have legitimate reasons to access its internals. That's why protected fields are used more often, even though they are not supported by the language syntax.
+
+````warn header="Private fields are not available as this[name]"
+Private fields are special.
+
+As we know, usually we can access fields using `this[name]`:
+
+```js
+class User {
+ ...
+ sayHi() {
+ let fieldName = "name";
+ alert(`Hello, ${*!*this[fieldName]*/!*}`);
+ }
+}
+```
+
+With private fields that's impossible: `this['#name']` doesn't work. That's a syntax limitation to ensure privacy.
+````
+
+## Summary
+
+In terms of OOP, delimiting of the internal interface from the external one is called [encapsulation](https://en.wikipedia.org/wiki/Encapsulation_(computer_programming)).
+
+It gives the following benefits:
+
+Protection for users, so that they don't shoot themselves in the foot
+: Imagine, there's a team of developers using a coffee machine. It was made by the "Best CoffeeMachine" company, and works fine, but a protective cover was removed. So the internal interface is exposed.
+
+ All developers are civilized -- they use the coffee machine as intended. But one of them, John, decided that he's the smartest one, and made some tweaks in the coffee machine internals. So the coffee machine failed two days later.
+
+ That's surely not John's fault, but rather the person who removed the protective cover and let John do his manipulations.
+
+ The same in programming. If a user of a class will change things not intended to be changed from the outside -- the consequences are unpredictable.
+
+Supportable
+: The situation in programming is more complex than with a real-life coffee machine, because we don't just buy it once. The code constantly undergoes development and improvement.
+
+ **If we strictly delimit the internal interface, then the developer of the class can freely change its internal properties and methods, even without informing the users.**
+
+ If you're a developer of such class, it's great to know that private methods can be safely renamed, their parameters can be changed, and even removed, because no external code depends on them.
+
+ For users, when a new version comes out, it may be a total overhaul internally, but still simple to upgrade if the external interface is the same.
+
+Hiding complexity
+: People adore using things that are simple. At least from outside. What's inside is a different thing.
+
+ Programmers are not an exception.
+
+ **It's always convenient when implementation details are hidden, and a simple, well-documented external interface is available.**
+
+To hide an internal interface we use either protected or private properties:
+
+- Protected fields start with `_`. That's a well-known convention, not enforced at the language level. Programmers should only access a field starting with `_` from its class and classes inheriting from it.
+- Private fields start with `#`. JavaScript makes sure we can only access those from inside the class.
+
+Right now, private fields are not well-supported among browsers, but can be polyfilled.
diff --git a/1-js/09-classes/05-private-protected-properties-methods/coffee-inside.jpg b/1-js/09-classes/04-private-protected-properties-methods/coffee-inside.jpg
similarity index 100%
rename from 1-js/09-classes/05-private-protected-properties-methods/coffee-inside.jpg
rename to 1-js/09-classes/04-private-protected-properties-methods/coffee-inside.jpg
diff --git a/1-js/09-classes/05-private-protected-properties-methods/coffee.jpg b/1-js/09-classes/04-private-protected-properties-methods/coffee.jpg
similarity index 100%
rename from 1-js/09-classes/05-private-protected-properties-methods/coffee.jpg
rename to 1-js/09-classes/04-private-protected-properties-methods/coffee.jpg
diff --git a/1-js/09-classes/04-static-properties-methods/animal-rabbit-static.png b/1-js/09-classes/04-static-properties-methods/animal-rabbit-static.png
deleted file mode 100644
index f6331e95aa..0000000000
Binary files a/1-js/09-classes/04-static-properties-methods/animal-rabbit-static.png and /dev/null differ
diff --git a/1-js/09-classes/04-static-properties-methods/animal-rabbit-static@2x.png b/1-js/09-classes/04-static-properties-methods/animal-rabbit-static@2x.png
deleted file mode 100644
index d515cb0f01..0000000000
Binary files a/1-js/09-classes/04-static-properties-methods/animal-rabbit-static@2x.png and /dev/null differ
diff --git a/1-js/09-classes/04-static-properties-methods/article.md b/1-js/09-classes/04-static-properties-methods/article.md
deleted file mode 100644
index 760641eaff..0000000000
--- a/1-js/09-classes/04-static-properties-methods/article.md
+++ /dev/null
@@ -1,226 +0,0 @@
-
-# Static properties and methods
-
-We can also assign a methods to the class function, not to its `"prototype"`. Such methods are called *static*.
-
-An example:
-
-```js run
-class User {
-*!*
- static staticMethod() {
-*/!*
- alert(this === User);
- }
-}
-
-User.staticMethod(); // true
-```
-
-That actually does the same as assigning it as a function property:
-
-```js
-function User() { }
-
-User.staticMethod = function() {
- alert(this === User);
-};
-```
-
-The value of `this` inside `User.staticMethod()` is the class constructor `User` itself (the "object before dot" rule).
-
-Usually, static methods are used to implement functions that belong to the class, but not to any particular object of it.
-
-For instance, we have `Article` objects and need a function to compare them. The natural choice would be `Article.compare`, like this:
-
-```js run
-class Article {
- constructor(title, date) {
- this.title = title;
- this.date = date;
- }
-
-*!*
- static compare(articleA, articleB) {
- return articleA.date - articleB.date;
- }
-*/!*
-}
-
-// usage
-let articles = [
- new Article("Mind", new Date(2019, 1, 1)),
- new Article("Body", new Date(2019, 0, 1)),
- new Article("JavaScript", new Date(2019, 11, 1))
-];
-
-*!*
-articles.sort(Article.compare);
-*/!*
-
-alert( articles[0].title ); // Body
-```
-
-Here `Article.compare` stands "over" the articles, as a means to compare them. It's not a method of an article, but rather of the whole class.
-
-Another example would be a so-called "factory" method. Imagine, we need few ways to create an article:
-
-1. Create by given parameters (`title`, `date` etc).
-2. Create an empty article with today's date.
-3. ...
-
-The first way can be implemented by the constructor. And for the second one we can make a static method of the class.
-
-Like `Article.createTodays()` here:
-
-```js run
-class Article {
- constructor(title, date) {
- this.title = title;
- this.date = date;
- }
-
-*!*
- static createTodays() {
- // remember, this = Article
- return new this("Today's digest", new Date());
- }
-*/!*
-}
-
-let article = Article.createTodays();
-
-alert( article.title ); // Todays digest
-```
-
-Now every time we need to create a today's digest, we can call `Article.createTodays()`. Once again, that's not a method of an article, but a method of the whole class.
-
-Static methods are also used in database-related classes to search/save/remove entries from the database, like this:
-
-```js
-// assuming Article is a special class for managing articles
-// static method to remove the article:
-Article.remove({id: 12345});
-```
-
-## Static properties
-
-[recent browser=Chrome]
-
-Static properties are also possible, just like regular class properties:
-
-```js run
-class Article {
- static publisher = "Ilya Kantor";
-}
-
-alert( Article.publisher ); // Ilya Kantor
-```
-
-That is the same as a direct assignment to `Article`:
-
-```js
-Article.publisher = "Ilya Kantor";
-```
-
-## Statics and inheritance
-
-Statics are inhereted, we can access `Parent.method` as `Child.method`.
-
-For instance, `Animal.compare` in the code below is inhereted and accessible as `Rabbit.compare`:
-
-```js run
-class Animal {
-
- constructor(name, speed) {
- this.speed = speed;
- this.name = name;
- }
-
- run(speed = 0) {
- this.speed += speed;
- alert(`${this.name} runs with speed ${this.speed}.`);
- }
-
-*!*
- static compare(animalA, animalB) {
- return animalA.speed - animalB.speed;
- }
-*/!*
-
-}
-
-// Inherit from Animal
-class Rabbit extends Animal {
- hide() {
- alert(`${this.name} hides!`);
- }
-}
-
-let rabbits = [
- new Rabbit("White Rabbit", 10),
- new Rabbit("Black Rabbit", 5)
-];
-
-*!*
-rabbits.sort(Rabbit.compare);
-*/!*
-
-rabbits[0].run(); // Black Rabbit runs with speed 5.
-```
-
-Now we can call `Rabbit.compare` assuming that the inherited `Animal.compare` will be called.
-
-How does it work? Again, using prototypes. As you might have already guessed, extends also gives `Rabbit` the `[[Prototype]]` reference to `Animal`.
-
-
-
-
-So, `Rabbit` function now inherits from `Animal` function. And `Animal` function normally has `[[Prototype]]` referencing `Function.prototype`, because it doesn't `extend` anything.
-
-Here, let's check that:
-
-```js run
-class Animal {}
-class Rabbit extends Animal {}
-
-// for static properties and methods
-alert(Rabbit.__proto__ === Animal); // true
-
-// and the next step is Function.prototype
-alert(Animal.__proto__ === Function.prototype); // true
-
-// that's in addition to the "normal" prototype chain for object methods
-alert(Rabbit.prototype.__proto__ === Animal.prototype);
-```
-
-This way `Rabbit` has access to all static methods of `Animal`.
-
-## Summary
-
-Static methods are used for the functionality that doesn't relate to a concrete class instance, doesn't require an instance to exist, but rather belongs to the class as a whole, like `Article.compare` -- a generic method to compare two articles.
-
-Static properties are used when we'd like to store class-level data, also not bound to an instance.
-
-The syntax is:
-
-```js
-class MyClass {
- static property = ...;
-
- static method() {
- ...
- }
-}
-```
-
-That's technically the same as assigning to the class itself:
-
-```js
-MyClass.property = ...
-MyClass.method = ...
-```
-
-Static properties are inherited.
-
-Technically, for `class B extends A` the prototype of the class `B` itself points to `A`: `B.[[Prototype]] = A`. So if a field is not found in `B`, the search continues in `A`.
diff --git a/1-js/09-classes/05-extend-natives/article.md b/1-js/09-classes/05-extend-natives/article.md
new file mode 100644
index 0000000000..28b4c6eb64
--- /dev/null
+++ b/1-js/09-classes/05-extend-natives/article.md
@@ -0,0 +1,89 @@
+
+# Extending built-in classes
+
+Built-in classes like Array, Map and others are extendable also.
+
+For instance, here `PowerArray` inherits from the native `Array`:
+
+```js run
+// add one more method to it (can do more)
+class PowerArray extends Array {
+ isEmpty() {
+ return this.length === 0;
+ }
+}
+
+let arr = new PowerArray(1, 2, 5, 10, 50);
+alert(arr.isEmpty()); // false
+
+let filteredArr = arr.filter(item => item >= 10);
+alert(filteredArr); // 10, 50
+alert(filteredArr.isEmpty()); // false
+```
+
+Please note a very interesting thing. Built-in methods like `filter`, `map` and others -- return new objects of exactly the inherited type `PowerArray`. Their internal implementation uses the object's `constructor` property for that.
+
+In the example above,
+```js
+arr.constructor === PowerArray
+```
+
+When `arr.filter()` is called, it internally creates the new array of results using exactly `arr.constructor`, not basic `Array`. That's actually very cool, because we can keep using `PowerArray` methods further on the result.
+
+Even more, we can customize that behavior.
+
+We can add a special static getter `Symbol.species` to the class. If it exists, it should return the constructor that JavaScript will use internally to create new entities in `map`, `filter` and so on.
+
+If we'd like built-in methods like `map` or `filter` to return regular arrays, we can return `Array` in `Symbol.species`, like here:
+
+```js run
+class PowerArray extends Array {
+ isEmpty() {
+ return this.length === 0;
+ }
+
+*!*
+ // built-in methods will use this as the constructor
+ static get [Symbol.species]() {
+ return Array;
+ }
+*/!*
+}
+
+let arr = new PowerArray(1, 2, 5, 10, 50);
+alert(arr.isEmpty()); // false
+
+// filter creates new array using arr.constructor[Symbol.species] as constructor
+let filteredArr = arr.filter(item => item >= 10);
+
+*!*
+// filteredArr is not PowerArray, but Array
+*/!*
+alert(filteredArr.isEmpty()); // Error: filteredArr.isEmpty is not a function
+```
+
+As you can see, now `.filter` returns `Array`. So the extended functionality is not passed any further.
+
+```smart header="Other collections work similarly"
+Other collections, such as `Map` and `Set`, work alike. They also use `Symbol.species`.
+```
+
+## No static inheritance in built-ins
+
+Built-in objects have their own static methods, for instance `Object.keys`, `Array.isArray` etc.
+
+As we already know, native classes extend each other. For instance, `Array` extends `Object`.
+
+Normally, when one class extends another, both static and non-static methods are inherited. That was thoroughly explained in the article [](info:static-properties-methods#statics-and-inheritance).
+
+But built-in classes are an exception. They don't inherit statics from each other.
+
+For example, both `Array` and `Date` inherit from `Object`, so their instances have methods from `Object.prototype`. But `Array.[[Prototype]]` does not reference `Object`, so there's no, for instance, `Array.keys()` (or `Date.keys()`) static method.
+
+Here's the picture structure for `Date` and `Object`:
+
+
+
+As you can see, there's no link between `Date` and `Object`. They are independent, only `Date.prototype` inherits from `Object.prototype`.
+
+That's an important difference of inheritance between built-in objects compared to what we get with `extends`.
diff --git a/1-js/09-classes/05-extend-natives/object-date-inheritance.svg b/1-js/09-classes/05-extend-natives/object-date-inheritance.svg
new file mode 100644
index 0000000000..be47d7fd96
--- /dev/null
+++ b/1-js/09-classes/05-extend-natives/object-date-inheritance.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/09-classes/05-private-protected-properties-methods/article.md b/1-js/09-classes/05-private-protected-properties-methods/article.md
deleted file mode 100644
index 82466331a0..0000000000
--- a/1-js/09-classes/05-private-protected-properties-methods/article.md
+++ /dev/null
@@ -1,330 +0,0 @@
-
-# Private and protected properties and methods
-
-One of the most important principles of object oriented programming -- delimiting internal interface from the external one.
-
-That is "a must" practice in developing anything more complex than a "hello world" app.
-
-To understand this, let's break away from development and turn our eyes into the real world.
-
-Usually, devices that we're using are quite complex. But delimiting the internal interface from the external one allows to use them without problems.
-
-## A real-life example
-
-For instance, a coffee machine. Simple from outside: a button, a display, a few holes...And, surely, the result -- great coffee! :)
-
-
-
-But inside... (a picture from the repair manual)
-
-
-
-A lot of details. But we can use it without knowing anything.
-
-Coffee machines are quite reliable, aren't they? We can use one for years, and only if something goes wrong -- bring it for repairs.
-
-The secret of reliability and simplicity of a coffee machine -- all details are well-tuned and *hidden* inside.
-
-If we remove the protective cover from the coffee machine, then using it will be much more complex (where to press?), and dangerous (it can electrocute).
-
-As we'll see, in programming objects are like coffee machines.
-
-But in order to hide inner details, we'll use not a protective cover, but rather special syntax of the language and conventions.
-
-## Internal and external interface
-
-In object-oriented programming, properties and methods are split into two groups:
-
-- *Internal interface* -- methods and properties, accessible from other methods of the class, but not from the outside.
-- *External interface* -- methods and properties, accessible also from outside the class.
-
-If we continue the analogy with the coffee machine -- what's hidden inside: a boiler tube, heating element, and so on -- is its internal interface.
-
-An internal interface is used for the object to work, its details use each other. For instance, a boiler tube is attached to the heating element.
-
-But from the outside a coffee machine is closed by the protective cover, so that no one can reach those. Details are hidden and inaccessible. We can use its features via the external interface.
-
-So, all we need to use an object is to know its external interface. We may be completely unaware how it works inside, and that's great.
-
-That was a general introduction.
-
-In JavaScript, there are three types of properties and members:
-
-- Public: accessible from anywhere. They comprise the external interface. Till now we were only using public properties and methods.
-- Private: accessible only from inside the class. These are for the internal interface.
-
-In many other languages there also exist "protected" fields: accessible only from inside the class and those extending it. They are also useful for the internal interface. They are in a sense more widespread than private ones, because we usually want inheriting classes to gain access to properly do the extension.
-
-Protected fields are not implemented in Javascript on the language level, but in practice they are very convenient, so they are emulated.
-
-In the next step we'll make a coffee machine in Javascript with all these types of properties. A coffee machine has a lot of details, we won't model them to stay simple (though we could).
-
-## Protecting "waterAmount"
-
-Let's make a simple coffee machine class first:
-
-```js run
-class CoffeeMachine {
- waterAmount = 0; // the amount of water inside
-
- constructor(power) {
- this.power = power;
- alert( `Created a coffee-machine, power: ${power}` );
- }
-
-}
-
-// create the coffee machine
-let coffeeMachine = new CoffeeMachine(100);
-
-// add water
-coffeeMachine.waterAmount = 200;
-```
-
-Right now the properties `waterAmount` and `power` are public. We can easily get/set them from the outside to any value.
-
-Let's change `waterAmount` property to protected to have more control over it. For instance, we don't want anyone to set it below zero.
-
-**Protected properties are usually prefixed with an underscore `_`.**
-
-That is not enforced on the language level, but there's a convention that such properties and methods should not be accessed from the outside. Most programmers follow it.
-
-So our property will be called `_waterAmount`:
-
-```js run
-class CoffeeMachine {
- _waterAmount = 0;
-
- set waterAmount(value) {
- if (value < 0) throw new Error("Negative water");
- this._waterAmount = value;
- }
-
- get waterAmount() {
- return this._waterAmount;
- }
-
- constructor(power) {
- this._power = power;
- }
-
-}
-
-// create the coffee machine
-let coffeeMachine = new CoffeeMachine(100);
-
-// add water
-coffeeMachine.waterAmount = -10; // Error: Negative water
-```
-
-Now the access is under control, so setting the water below zero fails.
-
-## Read-only "power"
-
-For `power` property, let's make it read-only. It sometimes happens that a property must be set at creation time only, and then never modified.
-
-That's exactly the case for a coffee machine: power never changes.
-
-To do so, we only need to make getter, but not the setter:
-
-```js run
-class CoffeeMachine {
- // ...
-
- constructor(power) {
- this._power = power;
- }
-
- get power() {
- return this._power;
- }
-
-}
-
-// create the coffee machine
-let coffeeMachine = new CoffeeMachine(100);
-
-alert(`Power is: ${coffeeMachine.power}W`); // Power is: 100W
-
-coffeeMachine.power = 25; // Error (no setter)
-```
-
-````smart header="Getter/setter functions"
-Here we used getter/setter syntax.
-
-But most of the time `get.../set...` functions are preferred, like this:
-
-```js
-class CoffeeMachine {
- _waterAmount = 0;
-
- *!*setWaterAmount(value)*/!* {
- if (value < 0) throw new Error("Negative water");
- this._waterAmount = value;
- }
-
- *!*getWaterAmount()*/!* {
- return this.waterAmount;
- }
-}
-
-new CoffeeMachine().setWaterAmount(100);
-```
-
-That looks a bit longer, but functions are more flexible. They can accept multiple arguments (even if we don't need them right now). So, for the future, just in case we need to refactor something, functions are a safer choise.
-
-Surely, there's a tradeoff. On the other hand, get/set syntax is shorter, so ultimately there's no strict rule, it's up to you to decide.
-````
-
-```smart header="Protected fields are inherited"
-If we inherit `class MegaMachine extends CoffeeMachine`, then nothing prevents us from accessing `this._waterAmount` or `this._power` from the methods of the new class.
-
-So protected fields are naturally inheritable. Unlike private ones that we'll see below.
-```
-
-## Private "#waterLimit"
-
-[recent browser=none]
-
-There's a finished Javascript proposal, almost in the standard, that provides language-level support for private properties and methods.
-
-Privates should start with `#`. They are only accessible from inside the class.
-
-For instance, here we add a private `#waterLimit` property and extract the water-checking logic into a separate method:
-
-```js
-class CoffeeMachine {
-*!*
- #waterLimit = 200;
-*/!*
-
-*!*
- #checkWater(water) {
- if (value < 0) throw new Error("Negative water");
- if (value > this.#waterLimit) throw new Error("Too much water");
- }
-*/!*
-
- _waterAmount = 0;
-
- set waterAmount(value) {
-*!*
- this.#checkWater(value);
-*/!*
- this._waterAmount = value;
- }
-
- get waterAmount() {
- return this.waterAmount;
- }
-
-}
-
-let coffeeMachine = new CoffeeMachine();
-
-*!*
-coffeeMachine.#checkWater(); // Error
-coffeeMachine.#waterLimit = 1000; // Error
-*/!*
-
-coffeeMachine.waterAmount = 100; // Works
-```
-
-On the language level, `#` is a special sign that the field is private. We can't access it from outside or from inhereting classes.
-
-Private fields do not conflict with public ones. We can have both private `#waterAmount` and public `waterAmount` fields at the same time.
-
-For instance, let's make `waterAmount` an accessor for `#waterAmount`:
-
-```js run
-class CoffeeMachine {
-
- #waterAmount = 0;
-
- get waterAmount() {
- return this.#waterAmount;
- }
-
- set waterAmount(value) {
- if (value < 0) throw new Error("Negative water");
- this.#waterAmount = value;
- }
-}
-
-let machine = new CoffeeMachine();
-
-machine.waterAmount = 100;
-alert(machine.#waterAmount); // Error
-```
-
-Unlike protected ones, private fields are enforced by the language itselfs. That's a good thing.
-
-But if we inherit from `CoffeeMachine`, then we'll have no direct access to `#waterAmount`. We'll need to rely on `waterAmount` getter/setter:
-
-```js
-class CoffeeMachine extends CoffeeMachine() {
- method() {
-*!*
- alert( this.#waterAmount ); // Error: can only access from CoffeeMachine
-*/!*
- }
-}
-```
-
-In many scenarios such limitation is too severe. If we extend a `CoffeeMachine`, we may have legitimate reason to access its internals. That's why protected fields are used most of the time, even though they are not supported by the language syntax.
-
-````warn
-Private fields are special.
-
-Remember, usually we can access fields by this[name]:
-
-```js
-class User {
- ...
- sayHi() {
- let fieldName = "name";
- alert(`Hello, ${this[fieldName]}`);
- }
-}
-```
-
-With private fields that's impossible: `this['#name']` doesn't work. That's a syntax limitation to ensure privacy.
-````
-
-## Summary
-
-In terms of OOP, delimiting of the internal interface from the external one is called [encapsulation]("https://en.wikipedia.org/wiki/Encapsulation_(computer_programming)").
-
-It gives the following benefits:
-
-Protection for users, so that they don't shoot themselves in the feet
-: Imagine, there's a team of developers using a coffee machine. It was made by the "Best CoffeeMachine" company, and works fine, but a protective cover was removed. So the internal interface is exposed.
-
- All developers are civilized -- they use the coffee machine as intended. But one of them, John, decided that he's the smartest one, and made some tweaks in the coffee machine internals. So the coffee machine failed two days later.
-
- That's surely not John's fault, but rather the person who removed the protective cover and let John do his manipulations.
-
- The same in programming. If a user of a class will change things not intended to be changed from the outside -- the consequences are unpredictable.
-
-Supportable
-: The situation in programming is more complex than with a real-life coffee machine, because we don't just buy it once. The code constantly undergoes development and improvement.
-
- **If we strictly delimit the internal interface, then the developer of the class can freely change its internal properties and methods, even without informing the users..**
-
- It's much easier to develop, if you know that certain methods can be renamed, their parameters can be changed, and even removed, because no external code depends on them.
-
- For users, when a new version comes out, it may be a total overhaul, but still simple to upgrade if the external interface is the same.
-
-Hiding complexity
-: People adore to use things that are simple. At least from outside. What's inside is a different thing.
-
- Programmers are not an exception.
-
- **It's always convenient when implementation details are hidden, and a simple, well-documented external interface is available.**
-
-To hide internal interface we use either protected or public properties:
-
-- Protected fields start with `_`. That's a well-known convention, not enforced at the language level. Programmers should only access a field starting with `_` from its class and classes inheriting from it.
-- Private fields start with `#`. Javascript makes sure we only can access those from inside the class.
-
-Right now, private fields are not well-supported among browsers, but can be polyfilled.
diff --git a/1-js/09-classes/06-extend-natives/article.md b/1-js/09-classes/06-extend-natives/article.md
deleted file mode 100644
index 24757abe2e..0000000000
--- a/1-js/09-classes/06-extend-natives/article.md
+++ /dev/null
@@ -1,82 +0,0 @@
-
-# Extending build-in classes
-
-Built-in classes like Array, Map and others are extendable also.
-
-For instance, here `PowerArray` inherits from the native `Array`:
-
-```js run
-// add one more method to it (can do more)
-class PowerArray extends Array {
- isEmpty() {
- return this.length === 0;
- }
-}
-
-let arr = new PowerArray(1, 2, 5, 10, 50);
-alert(arr.isEmpty()); // false
-
-let filteredArr = arr.filter(item => item >= 10);
-alert(filteredArr); // 10, 50
-alert(filteredArr.isEmpty()); // false
-```
-
-Please note a very interesting thing. Built-in methods like `filter`, `map` and others -- return new objects of exactly the inherited type. They rely on the `constructor` property to do so.
-
-In the example above,
-```js
-arr.constructor === PowerArray
-```
-
-So when `arr.filter()` is called, it internally creates the new array of results exactly as `new PowerArray`.
-That's actually very cool, because we can keep using `PowerArray` methods further o the result.
-
-Even more, we can customize that behavior.
-
-There's a special static getter `Symbol.species`, if exists, it returns the constructor to use in such cases.
-
-If we'd like built-in methods like `map`, `filter` will return regular arrays, we can return `Array` in `Symbol.species`, like here:
-
-```js run
-class PowerArray extends Array {
- isEmpty() {
- return this.length === 0;
- }
-
-*!*
- // built-in methods will use this as the constructor
- static get [Symbol.species]() {
- return Array;
- }
-*/!*
-}
-
-let arr = new PowerArray(1, 2, 5, 10, 50);
-alert(arr.isEmpty()); // false
-
-// filter creates new array using arr.constructor[Symbol.species] as constructor
-let filteredArr = arr.filter(item => item >= 10);
-
-*!*
-// filteredArr is not PowerArray, but Array
-*/!*
-alert(filteredArr.isEmpty()); // Error: filteredArr.isEmpty is not a function
-```
-
-As you can see, now `.filter` returns `Array`. So the extended functionality is not passed any further.
-
-## No static inheritance in built-ins
-
-Built-in objects have their own static methods, for instance `Object.keys`, `Array.isArray` etc.
-
-And we've already been talking about native classes extending each other: `Array.[[Prototype]] = Object`.
-
-But statics are an exception. Built-in classes don't inherit static properties from each other.
-
-In other words, the prototype of build-in constructor `Array` does not point to `Object`. This way `Array` and `Date` do not have `Array.keys` or `Date.keys`. And that feels natural.
-
-Here's the picture structure for `Date` and `Object`:
-
-
-
-Note, there's no link between `Date` and `Object`. Both `Object` and `Date` exist independently. `Date.prototype` inherits from `Object.prototype`, but that's all.
diff --git a/1-js/09-classes/06-extend-natives/object-date-inheritance.png b/1-js/09-classes/06-extend-natives/object-date-inheritance.png
deleted file mode 100644
index b5f1932cd6..0000000000
Binary files a/1-js/09-classes/06-extend-natives/object-date-inheritance.png and /dev/null differ
diff --git a/1-js/09-classes/06-extend-natives/object-date-inheritance@2x.png b/1-js/09-classes/06-extend-natives/object-date-inheritance@2x.png
deleted file mode 100644
index 38276d45e7..0000000000
Binary files a/1-js/09-classes/06-extend-natives/object-date-inheritance@2x.png and /dev/null differ
diff --git a/1-js/09-classes/07-instanceof/1-strange-instanceof/solution.md b/1-js/09-classes/06-instanceof/1-strange-instanceof/solution.md
similarity index 100%
rename from 1-js/09-classes/07-instanceof/1-strange-instanceof/solution.md
rename to 1-js/09-classes/06-instanceof/1-strange-instanceof/solution.md
diff --git a/1-js/09-classes/06-instanceof/1-strange-instanceof/task.md b/1-js/09-classes/06-instanceof/1-strange-instanceof/task.md
new file mode 100644
index 0000000000..5b8dc7de3c
--- /dev/null
+++ b/1-js/09-classes/06-instanceof/1-strange-instanceof/task.md
@@ -0,0 +1,20 @@
+importance: 5
+
+---
+
+# Strange instanceof
+
+In the code below, why does `instanceof` return `true`? We can easily see that `a` is not created by `B()`.
+
+```js run
+function A() {}
+function B() {}
+
+A.prototype = B.prototype = {};
+
+let a = new A();
+
+*!*
+alert( a instanceof B ); // true
+*/!*
+```
diff --git a/1-js/09-classes/06-instanceof/article.md b/1-js/09-classes/06-instanceof/article.md
new file mode 100644
index 0000000000..f9db989ca9
--- /dev/null
+++ b/1-js/09-classes/06-instanceof/article.md
@@ -0,0 +1,218 @@
+# Class checking: "instanceof"
+
+The `instanceof` operator allows to check whether an object belongs to a certain class. It also takes inheritance into account.
+
+Such a check may be necessary in many cases. For example, it can be used for building a *polymorphic* function, the one that treats arguments differently depending on their type.
+
+## The instanceof operator [#ref-instanceof]
+
+The syntax is:
+```js
+obj instanceof Class
+```
+
+It returns `true` if `obj` belongs to the `Class` or a class inheriting from it.
+
+For instance:
+
+```js run
+class Rabbit {}
+let rabbit = new Rabbit();
+
+// is it an object of Rabbit class?
+*!*
+alert( rabbit instanceof Rabbit ); // true
+*/!*
+```
+
+It also works with constructor functions:
+
+```js run
+*!*
+// instead of class
+function Rabbit() {}
+*/!*
+
+alert( new Rabbit() instanceof Rabbit ); // true
+```
+
+...And with built-in classes like `Array`:
+
+```js run
+let arr = [1, 2, 3];
+alert( arr instanceof Array ); // true
+alert( arr instanceof Object ); // true
+```
+
+Please note that `arr` also belongs to the `Object` class. That's because `Array` prototypically inherits from `Object`.
+
+Normally, `instanceof` examines the prototype chain for the check. We can also set a custom logic in the static method `Symbol.hasInstance`.
+
+The algorithm of `obj instanceof Class` works roughly as follows:
+
+1. If there's a static method `Symbol.hasInstance`, then just call it: `Class[Symbol.hasInstance](obj)`. It should return either `true` or `false`, and we're done. That's how we can customize the behavior of `instanceof`.
+
+ For example:
+
+ ```js run
+ // setup instanceOf check that assumes that
+ // anything with canEat property is an animal
+ class Animal {
+ static [Symbol.hasInstance](obj) {
+ if (obj.canEat) return true;
+ }
+ }
+
+ let obj = { canEat: true };
+
+ alert(obj instanceof Animal); // true: Animal[Symbol.hasInstance](obj) is called
+ ```
+
+2. Most classes do not have `Symbol.hasInstance`. In that case, the standard logic is used: `obj instanceOf Class` checks whether `Class.prototype` is equal to one of the prototypes in the `obj` prototype chain.
+
+ In other words, compare one after another:
+ ```js
+ obj.__proto__ === Class.prototype?
+ obj.__proto__.__proto__ === Class.prototype?
+ obj.__proto__.__proto__.__proto__ === Class.prototype?
+ ...
+ // if any answer is true, return true
+ // otherwise, if we reached the end of the chain, return false
+ ```
+
+ In the example above `rabbit.__proto__ === Rabbit.prototype`, so that gives the answer immediately.
+
+ In the case of an inheritance, the match will be at the second step:
+
+ ```js run
+ class Animal {}
+ class Rabbit extends Animal {}
+
+ let rabbit = new Rabbit();
+ *!*
+ alert(rabbit instanceof Animal); // true
+ */!*
+
+ // rabbit.__proto__ === Animal.prototype (no match)
+ *!*
+ // rabbit.__proto__.__proto__ === Animal.prototype (match!)
+ */!*
+ ```
+
+Here's the illustration of what `rabbit instanceof Animal` compares with `Animal.prototype`:
+
+
+
+By the way, there's also a method [objA.isPrototypeOf(objB)](mdn:js/object/isPrototypeOf), that returns `true` if `objA` is somewhere in the chain of prototypes for `objB`. So the test of `obj instanceof Class` can be rephrased as `Class.prototype.isPrototypeOf(obj)`.
+
+It's funny, but the `Class` constructor itself does not participate in the check! Only the chain of prototypes and `Class.prototype` matters.
+
+That can lead to interesting consequences when a `prototype` property is changed after the object is created.
+
+Like here:
+
+```js run
+function Rabbit() {}
+let rabbit = new Rabbit();
+
+// changed the prototype
+Rabbit.prototype = {};
+
+// ...not a rabbit any more!
+*!*
+alert( rabbit instanceof Rabbit ); // false
+*/!*
+```
+
+## Bonus: Object.prototype.toString for the type
+
+We already know that plain objects are converted to string as `[object Object]`:
+
+```js run
+let obj = {};
+
+alert(obj); // [object Object]
+alert(obj.toString()); // the same
+```
+
+That's their implementation of `toString`. But there's a hidden feature that makes `toString` actually much more powerful than that. We can use it as an extended `typeof` and an alternative for `instanceof`.
+
+Sounds strange? Indeed. Let's demystify.
+
+By [specification](https://tc39.github.io/ecma262/#sec-object.prototype.tostring), the built-in `toString` can be extracted from the object and executed in the context of any other value. And its result depends on that value.
+
+- For a number, it will be `[object Number]`
+- For a boolean, it will be `[object Boolean]`
+- For `null`: `[object Null]`
+- For `undefined`: `[object Undefined]`
+- For arrays: `[object Array]`
+- ...etc (customizable).
+
+Let's demonstrate:
+
+```js run
+// copy toString method into a variable for convenience
+let objectToString = Object.prototype.toString;
+
+// what type is this?
+let arr = [];
+
+alert( objectToString.call(arr) ); // [object *!*Array*/!*]
+```
+
+Here we used [call](mdn:js/function/call) as described in the chapter [](info:call-apply-decorators) to execute the function `objectToString` in the context `this=arr`.
+
+Internally, the `toString` algorithm examines `this` and returns the corresponding result. More examples:
+
+```js run
+let s = Object.prototype.toString;
+
+alert( s.call(123) ); // [object Number]
+alert( s.call(null) ); // [object Null]
+alert( s.call(alert) ); // [object Function]
+```
+
+### Symbol.toStringTag
+
+The behavior of Object `toString` can be customized using a special object property `Symbol.toStringTag`.
+
+For instance:
+
+```js run
+let user = {
+ [Symbol.toStringTag]: "User"
+};
+
+alert( {}.toString.call(user) ); // [object User]
+```
+
+For most environment-specific objects, there is such a property. Here are some browser specific examples:
+
+```js run
+// toStringTag for the environment-specific object and class:
+alert( window[Symbol.toStringTag]); // Window
+alert( XMLHttpRequest.prototype[Symbol.toStringTag] ); // XMLHttpRequest
+
+alert( {}.toString.call(window) ); // [object Window]
+alert( {}.toString.call(new XMLHttpRequest()) ); // [object XMLHttpRequest]
+```
+
+As you can see, the result is exactly `Symbol.toStringTag` (if exists), wrapped into `[object ...]`.
+
+At the end we have "typeof on steroids" that not only works for primitive data types, but also for built-in objects and even can be customized.
+
+We can use `{}.toString.call` instead of `instanceof` for built-in objects when we want to get the type as a string rather than just to check.
+
+## Summary
+
+Let's summarize the type-checking methods that we know:
+
+| | works for | returns |
+|---------------|-------------|---------------|
+| `typeof` | primitives | string |
+| `{}.toString` | primitives, built-in objects, objects with `Symbol.toStringTag` | string |
+| `instanceof` | objects | true/false |
+
+As we can see, `{}.toString` is technically a "more advanced" `typeof`.
+
+And `instanceof` operator really shines when we are working with a class hierarchy and want to check for the class taking into account inheritance.
diff --git a/1-js/09-classes/06-instanceof/instanceof.svg b/1-js/09-classes/06-instanceof/instanceof.svg
new file mode 100644
index 0000000000..d63b03a8a2
--- /dev/null
+++ b/1-js/09-classes/06-instanceof/instanceof.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/09-classes/07-instanceof/1-strange-instanceof/task.md b/1-js/09-classes/07-instanceof/1-strange-instanceof/task.md
deleted file mode 100644
index e9481912ae..0000000000
--- a/1-js/09-classes/07-instanceof/1-strange-instanceof/task.md
+++ /dev/null
@@ -1,20 +0,0 @@
-importance: 5
-
----
-
-# Strange instanceof
-
-Why `instanceof` below returns `true`? We can easily see that `a` is not created by `B()`.
-
-```js run
-function A() {}
-function B() {}
-
-A.prototype = B.prototype = {};
-
-let a = new A();
-
-*!*
-alert( a instanceof B ); // true
-*/!*
-```
diff --git a/1-js/09-classes/07-instanceof/article.md b/1-js/09-classes/07-instanceof/article.md
deleted file mode 100644
index 702c9e6b20..0000000000
--- a/1-js/09-classes/07-instanceof/article.md
+++ /dev/null
@@ -1,211 +0,0 @@
-# Class checking: "instanceof"
-
-The `instanceof` operator allows to check whether an object belongs to a certain class. It also takes inheritance into account.
-
-Such a check may be necessary in many cases, here we'll use it for building a *polymorphic* function, the one that treats arguments differently depending on their type.
-
-## The instanceof operator [#ref-instanceof]
-
-The syntax is:
-```js
-obj instanceof Class
-```
-
-It returns `true` if `obj` belongs to the `Class` (or a class inheriting from it).
-
-For instance:
-
-```js run
-class Rabbit {}
-let rabbit = new Rabbit();
-
-// is it an object of Rabbit class?
-*!*
-alert( rabbit instanceof Rabbit ); // true
-*/!*
-```
-
-It also works with constructor functions:
-
-```js run
-*!*
-// instead of class
-function Rabbit() {}
-*/!*
-
-alert( new Rabbit() instanceof Rabbit ); // true
-```
-
-...And with built-in classes like `Array`:
-
-```js run
-let arr = [1, 2, 3];
-alert( arr instanceof Array ); // true
-alert( arr instanceof Object ); // true
-```
-
-Please note that `arr` also belongs to the `Object` class. That's because `Array` prototypally inherits from `Object`.
-
-The `instanceof` operator examines the prototype chain for the check, and is also fine-tunable using the static method `Symbol.hasInstance`.
-
-The algorithm of `obj instanceof Class` works roughly as follows:
-
-1. If there's a static method `Symbol.hasInstance`, then use it. Like this:
-
- ```js run
- // assume anything that canEat is an animal
- class Animal {
- static [Symbol.hasInstance](obj) {
- if (obj.canEat) return true;
- }
- }
-
- let obj = { canEat: true };
- alert(obj instanceof Animal); // true: Animal[Symbol.hasInstance](obj) is called
- ```
-
-2. Most classes do not have `Symbol.hasInstance`. In that case, check if `Class.prototype` equals to one of prototypes in the `obj` prototype chain.
-
- In other words, compare:
- ```js
- obj.__proto__ === Class.prototype
- obj.__proto__.__proto__ === Class.prototype
- obj.__proto__.__proto__.__proto__ === Class.prototype
- ...
- ```
-
- In the example above `Rabbit.prototype === rabbit.__proto__`, so that gives the answer immediately.
-
- In the case of an inheritance, `rabbit` is an instance of the parent class as well:
-
- ```js run
- class Animal {}
- class Rabbit extends Animal {}
-
- let rabbit = new Rabbit();
- *!*
- alert(rabbit instanceof Animal); // true
- */!*
- // rabbit.__proto__ === Rabbit.prototype
- // rabbit.__proto__.__proto__ === Animal.prototype (match!)
- ```
-
-Here's the illustration of what `rabbit instanceof Animal` compares with `Animal.prototype`:
-
-
-
-By the way, there's also a method [objA.isPrototypeOf(objB)](mdn:js/object/isPrototypeOf), that returns `true` if `objA` is somewhere in the chain of prototypes for `objB`. So the test of `obj instanceof Class` can be rephrased as `Class.prototype.isPrototypeOf(obj)`.
-
-That's funny, but the `Class` constructor itself does not participate in the check! Only the chain of prototypes and `Class.prototype` matters.
-
-That can lead to interesting consequences when `prototype` is changed.
-
-Like here:
-
-```js run
-function Rabbit() {}
-let rabbit = new Rabbit();
-
-// changed the prototype
-Rabbit.prototype = {};
-
-// ...not a rabbit any more!
-*!*
-alert( rabbit instanceof Rabbit ); // false
-*/!*
-```
-
-That's one of the reasons to avoid changing `prototype`. Just to keep safe.
-
-## Bonus: Object toString for the type
-
-We already know that plain objects are converted to string as `[object Object]`:
-
-```js run
-let obj = {};
-
-alert(obj); // [object Object]
-alert(obj.toString()); // the same
-```
-
-That's their implementation of `toString`. But there's a hidden feature that makes `toString` actually much more powerful than that. We can use it as an extended `typeof` and an alternative for `instanceof`.
-
-Sounds strange? Indeed. Let's demystify.
-
-By [specification](https://tc39.github.io/ecma262/#sec-object.prototype.tostring), the built-in `toString` can be extracted from the object and executed in the context of any other value. And its result depends on that value.
-
-- For a number, it will be `[object Number]`
-- For a boolean, it will be `[object Boolean]`
-- For `null`: `[object Null]`
-- For `undefined`: `[object Undefined]`
-- For arrays: `[object Array]`
-- ...etc (customizable).
-
-Let's demonstrate:
-
-```js run
-// copy toString method into a variable for convenience
-let objectToString = Object.prototype.toString;
-
-// what type is this?
-let arr = [];
-
-alert( objectToString.call(arr) ); // [object Array]
-```
-
-Here we used [call](mdn:js/function/call) as described in the chapter [](info:call-apply-decorators) to execute the function `objectToString` in the context `this=arr`.
-
-Internally, the `toString` algorithm examines `this` and returns the corresponding result. More examples:
-
-```js run
-let s = Object.prototype.toString;
-
-alert( s.call(123) ); // [object Number]
-alert( s.call(null) ); // [object Null]
-alert( s.call(alert) ); // [object Function]
-```
-
-### Symbol.toStringTag
-
-The behavior of Object `toString` can be customized using a special object property `Symbol.toStringTag`.
-
-For instance:
-
-```js run
-let user = {
- [Symbol.toStringTag]: "User"
-};
-
-alert( {}.toString.call(user) ); // [object User]
-```
-
-For most environment-specific objects, there is such a property. Here are few browser specific examples:
-
-```js run
-// toStringTag for the envinronment-specific object and class:
-alert( window[Symbol.toStringTag]); // window
-alert( XMLHttpRequest.prototype[Symbol.toStringTag] ); // XMLHttpRequest
-
-alert( {}.toString.call(window) ); // [object Window]
-alert( {}.toString.call(new XMLHttpRequest()) ); // [object XMLHttpRequest]
-```
-
-As you can see, the result is exactly `Symbol.toStringTag` (if exists), wrapped into `[object ...]`.
-
-At the end we have "typeof on steroids" that not only works for primitive data types, but also for built-in objects and even can be customized.
-
-It can be used instead of `instanceof` for built-in objects when we want to get the type as a string rather than just to check.
-
-## Summary
-
-Let's recap the type-checking methods that we know:
-
-| | works for | returns |
-|---------------|-------------|---------------|
-| `typeof` | primitives | string |
-| `{}.toString` | primitives, built-in objects, objects with `Symbol.toStringTag` | string |
-| `instanceof` | objects | true/false |
-
-As we can see, `{}.toString` is technically a "more advanced" `typeof`.
-
-And `instanceof` operator really shines when we are working with a class hierarchy and want to check for the class taking into account inheritance.
diff --git a/1-js/09-classes/07-instanceof/instanceof.png b/1-js/09-classes/07-instanceof/instanceof.png
deleted file mode 100644
index eb43cb3d50..0000000000
Binary files a/1-js/09-classes/07-instanceof/instanceof.png and /dev/null differ
diff --git a/1-js/09-classes/07-instanceof/instanceof@2x.png b/1-js/09-classes/07-instanceof/instanceof@2x.png
deleted file mode 100644
index f6e0657551..0000000000
Binary files a/1-js/09-classes/07-instanceof/instanceof@2x.png and /dev/null differ
diff --git a/1-js/09-classes/07-mixins/article.md b/1-js/09-classes/07-mixins/article.md
new file mode 100644
index 0000000000..526b832efa
--- /dev/null
+++ b/1-js/09-classes/07-mixins/article.md
@@ -0,0 +1,208 @@
+# Mixins
+
+In JavaScript we can only inherit from a single object. There can be only one `[[Prototype]]` for an object. And a class may extend only one other class.
+
+But sometimes that feels limiting. For instance, we have a class `StreetSweeper` and a class `Bicycle`, and want to make their mix: a `StreetSweepingBicycle`.
+
+Or we have a class `User` and a class `EventEmitter` that implements event generation, and we'd like to add the functionality of `EventEmitter` to `User`, so that our users can emit events.
+
+There's a concept that can help here, called "mixins".
+
+As defined in Wikipedia, a [mixin](https://en.wikipedia.org/wiki/Mixin) is a class containing methods that can be used by other classes without a need to inherit from it.
+
+In other words, a *mixin* provides methods that implement a certain behavior, but we do not use it alone, we use it to add the behavior to other classes.
+
+## A mixin example
+
+The simplest way to implement a mixin in JavaScript is to make an object with useful methods, so that we can easily merge them into a prototype of any class.
+
+For instance here the mixin `sayHiMixin` is used to add some "speech" for `User`:
+
+```js run
+*!*
+// mixin
+*/!*
+let sayHiMixin = {
+ sayHi() {
+ alert(`Hello ${this.name}`);
+ },
+ sayBye() {
+ alert(`Bye ${this.name}`);
+ }
+};
+
+*!*
+// usage:
+*/!*
+class User {
+ constructor(name) {
+ this.name = name;
+ }
+}
+
+// copy the methods
+Object.assign(User.prototype, sayHiMixin);
+
+// now User can say hi
+new User("Dude").sayHi(); // Hello Dude!
+```
+
+There's no inheritance, but a simple method copying. So `User` may inherit from another class and also include the mixin to "mix-in" the additional methods, like this:
+
+```js
+class User extends Person {
+ // ...
+}
+
+Object.assign(User.prototype, sayHiMixin);
+```
+
+Mixins can make use of inheritance inside themselves.
+
+For instance, here `sayHiMixin` inherits from `sayMixin`:
+
+```js run
+let sayMixin = {
+ say(phrase) {
+ alert(phrase);
+ }
+};
+
+let sayHiMixin = {
+ __proto__: sayMixin, // (or we could use Object.setPrototypeOf to set the prototype here)
+
+ sayHi() {
+ *!*
+ // call parent method
+ */!*
+ super.say(`Hello ${this.name}`); // (*)
+ },
+ sayBye() {
+ super.say(`Bye ${this.name}`); // (*)
+ }
+};
+
+class User {
+ constructor(name) {
+ this.name = name;
+ }
+}
+
+// copy the methods
+Object.assign(User.prototype, sayHiMixin);
+
+// now User can say hi
+new User("Dude").sayHi(); // Hello Dude!
+```
+
+Please note that the call to the parent method `super.say()` from `sayHiMixin` (at lines labelled with `(*)`) looks for the method in the prototype of that mixin, not the class.
+
+Here's the diagram (see the right part):
+
+
+
+That's because methods `sayHi` and `sayBye` were initially created in `sayHiMixin`. So even though they got copied, their `[[HomeObject]]` internal property references `sayHiMixin`, as shown in the picture above.
+
+As `super` looks for parent methods in `[[HomeObject]].[[Prototype]]`, that means it searches `sayHiMixin.[[Prototype]]`.
+
+## EventMixin
+
+Now let's make a mixin for real life.
+
+An important feature of many browser objects (for instance) is that they can generate events. Events are a great way to "broadcast information" to anyone who wants it. So let's make a mixin that allows us to easily add event-related functions to any class/object.
+
+- The mixin will provide a method `.trigger(name, [...data])` to "generate an event" when something important happens to it. The `name` argument is a name of the event, optionally followed by additional arguments with event data.
+- Also the method `.on(name, handler)` that adds `handler` function as the listener to events with the given name. It will be called when an event with the given `name` triggers, and get the arguments from the `.trigger` call.
+- ...And the method `.off(name, handler)` that removes the `handler` listener.
+
+After adding the mixin, an object `user` will be able to generate an event `"login"` when the visitor logs in. And another object, say, `calendar` may want to listen for such events to load the calendar for the logged-in person.
+
+Or, a `menu` can generate the event `"select"` when a menu item is selected, and other objects may assign handlers to react on that event. And so on.
+
+Here's the code:
+
+```js run
+let eventMixin = {
+ /**
+ * Subscribe to event, usage:
+ * menu.on('select', function(item) { ... }
+ */
+ on(eventName, handler) {
+ if (!this._eventHandlers) this._eventHandlers = {};
+ if (!this._eventHandlers[eventName]) {
+ this._eventHandlers[eventName] = [];
+ }
+ this._eventHandlers[eventName].push(handler);
+ },
+
+ /**
+ * Cancel the subscription, usage:
+ * menu.off('select', handler)
+ */
+ off(eventName, handler) {
+ let handlers = this._eventHandlers?.[eventName];
+ if (!handlers) return;
+ for (let i = 0; i < handlers.length; i++) {
+ if (handlers[i] === handler) {
+ handlers.splice(i--, 1);
+ }
+ }
+ },
+
+ /**
+ * Generate an event with the given name and data
+ * this.trigger('select', data1, data2);
+ */
+ trigger(eventName, ...args) {
+ if (!this._eventHandlers?.[eventName]) {
+ return; // no handlers for that event name
+ }
+
+ // call the handlers
+ this._eventHandlers[eventName].forEach(handler => handler.apply(this, args));
+ }
+};
+```
+
+
+- `.on(eventName, handler)` -- assigns function `handler` to run when the event with that name occurs. Technically, there's an `_eventHandlers` property that stores an array of handlers for each event name, and it just adds it to the list.
+- `.off(eventName, handler)` -- removes the function from the handlers list.
+- `.trigger(eventName, ...args)` -- generates the event: all handlers from `_eventHandlers[eventName]` are called, with a list of arguments `...args`.
+
+Usage:
+
+```js run
+// Make a class
+class Menu {
+ choose(value) {
+ this.trigger("select", value);
+ }
+}
+// Add the mixin with event-related methods
+Object.assign(Menu.prototype, eventMixin);
+
+let menu = new Menu();
+
+// add a handler, to be called on selection:
+*!*
+menu.on("select", value => alert(`Value selected: ${value}`));
+*/!*
+
+// triggers the event => the handler above runs and shows:
+// Value selected: 123
+menu.choose("123");
+```
+
+Now, if we'd like any code to react to a menu selection, we can listen for it with `menu.on(...)`.
+
+And `eventMixin` mixin makes it easy to add such behavior to as many classes as we'd like, without interfering with the inheritance chain.
+
+## Summary
+
+*Mixin* -- is a generic object-oriented programming term: a class that contains methods for other classes.
+
+Some other languages allow multiple inheritance. JavaScript does not support multiple inheritance, but mixins can be implemented by copying methods into prototype.
+
+We can use mixins as a way to augment a class by adding multiple behaviors, like event-handling as we have seen above.
+
+Mixins may become a point of conflict if they accidentally overwrite existing class methods. So generally one should think well about the naming methods of a mixin, to minimize the probability of that happening.
diff --git a/1-js/09-classes/07-mixins/head.html b/1-js/09-classes/07-mixins/head.html
new file mode 100644
index 0000000000..20e3a63547
--- /dev/null
+++ b/1-js/09-classes/07-mixins/head.html
@@ -0,0 +1,43 @@
+
diff --git a/1-js/09-classes/07-mixins/mixin-inheritance.svg b/1-js/09-classes/07-mixins/mixin-inheritance.svg
new file mode 100644
index 0000000000..1fdc223936
--- /dev/null
+++ b/1-js/09-classes/07-mixins/mixin-inheritance.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/09-classes/08-mixins/article.md b/1-js/09-classes/08-mixins/article.md
deleted file mode 100644
index bb51395e69..0000000000
--- a/1-js/09-classes/08-mixins/article.md
+++ /dev/null
@@ -1,205 +0,0 @@
-# Mixins
-
-In JavaScript we can only inherit from a single object. There can be only one `[[Prototype]]` for an object. And a class may extend only one other class.
-
-But sometimes that feels limiting. For instance, I have a class `StreetSweeper` and a class `Bicycle`, and want to make a `StreetSweepingBicycle`.
-
-Or, talking about programming, we have a class `Renderer` that implements templating and a class `EventEmitter` that implements event handling, and want to merge these functionalities together with a class `Page`, to make a page that can use templates and emit events.
-
-There's a concept that can help here, called "mixins".
-
-As defined in Wikipedia, a [mixin](https://en.wikipedia.org/wiki/Mixin) is a class that contains methods for use by other classes without having to be the parent class of those other classes.
-
-In other words, a *mixin* provides methods that implement a certain behavior, but we do not use it alone, we use it to add the behavior to other classes.
-
-## A mixin example
-
-The simplest way to make a mixin in JavaScript is to make an object with useful methods, so that we can easily merge them into a prototype of any class.
-
-For instance here the mixin `sayHiMixin` is used to add some "speech" for `User`:
-
-```js run
-*!*
-// mixin
-*/!*
-let sayHiMixin = {
- sayHi() {
- alert(`Hello ${this.name}`);
- },
- sayBye() {
- alert(`Bye ${this.name}`);
- }
-};
-
-*!*
-// usage:
-*/!*
-class User {
- constructor(name) {
- this.name = name;
- }
-}
-
-// copy the methods
-Object.assign(User.prototype, sayHiMixin);
-
-// now User can say hi
-new User("Dude").sayHi(); // Hello Dude!
-```
-
-There's no inheritance, but a simple method copying. So `User` may extend some other class and also include the mixin to "mix-in" the additional methods, like this:
-
-```js
-class User extends Person {
- // ...
-}
-
-Object.assign(User.prototype, sayHiMixin);
-```
-
-Mixins can make use of inheritance inside themselves.
-
-For instance, here `sayHiMixin` inherits from `sayMixin`:
-
-```js run
-let sayMixin = {
- say(phrase) {
- alert(phrase);
- }
-};
-
-let sayHiMixin = {
- __proto__: sayMixin, // (or we could use Object.create to set the prototype here)
-
- sayHi() {
- *!*
- // call parent method
- */!*
- super.say(`Hello ${this.name}`);
- },
- sayBye() {
- super.say(`Bye ${this.name}`);
- }
-};
-
-class User {
- constructor(name) {
- this.name = name;
- }
-}
-
-// copy the methods
-Object.assign(User.prototype, sayHiMixin);
-
-// now User can say hi
-new User("Dude").sayHi(); // Hello Dude!
-```
-
-Please note that the call to the parent method `super.say()` from `sayHiMixin` looks for the method in the prototype of that mixin, not the class.
-
-
-
-That's because methods from `sayHiMixin` have `[[HomeObject]]` set to it. So `super` actually means `sayHiMixin.__proto__`, not `User.__proto__`.
-
-## EventMixin
-
-Now let's make a mixin for real life.
-
-The important feature of many objects is working with events.
-
-That is: an object should have a method to "generate an event" when something important happens to it, and other objects should be able to "listen" to such events.
-
-An event must have a name and, optionally, bundle some additional data.
-
-For instance, an object `user` can generate an event `"login"` when the visitor logs in. And another object `calendar` may want to receive such events to load the calendar for the logged-in person.
-
-Or, a `menu` can generate the event `"select"` when a menu item is selected, and other objects may want to get that information and react on that event.
-
-Events is a way to "share information" with anyone who wants it. They can be useful in any class, so let's make a mixin for them:
-
-```js run
-let eventMixin = {
- /**
- * Subscribe to event, usage:
- * menu.on('select', function(item) { ... }
- */
- on(eventName, handler) {
- if (!this._eventHandlers) this._eventHandlers = {};
- if (!this._eventHandlers[eventName]) {
- this._eventHandlers[eventName] = [];
- }
- this._eventHandlers[eventName].push(handler);
- },
-
- /**
- * Cancel the subscription, usage:
- * menu.off('select', handler)
- */
- off(eventName, handler) {
- let handlers = this._eventHandlers && this._eventHandlers[eventName];
- if (!handlers) return;
- for (let i = 0; i < handlers.length; i++) {
- if (handlers[i] === handler) {
- handlers.splice(i--, 1);
- }
- }
- },
-
- /**
- * Generate the event and attach the data to it
- * this.trigger('select', data1, data2);
- */
- trigger(eventName, ...args) {
- if (!this._eventHandlers || !this._eventHandlers[eventName]) {
- return; // no handlers for that event name
- }
-
- // call the handlers
- this._eventHandlers[eventName].forEach(handler => handler.apply(this, args));
- }
-};
-```
-
-There are 3 methods here:
-
-1. `.on(eventName, handler)` -- assigns function `handler` to run when the event with that name happens. The handlers are stored in the `_eventHandlers` property.
-2. `.off(eventName, handler)` -- removes the function from the handlers list.
-3. `.trigger(eventName, ...args)` -- generates the event: all assigned handlers are called and `args` are passed as arguments to them.
-
-
-Usage:
-
-```js run
-// Make a class
-class Menu {
- choose(value) {
- this.trigger("select", value);
- }
-}
-// Add the mixin
-Object.assign(Menu.prototype, eventMixin);
-
-let menu = new Menu();
-
-// call the handler on selection:
-*!*
-menu.on("select", value => alert(`Value selected: ${value}`));
-*/!*
-
-// triggers the event => shows Value selected: 123
-menu.choose("123"); // value selected
-```
-
-Now if we have the code interested to react on user selection, we can bind it with `menu.on(...)`.
-
-And the `eventMixin` can add such behavior to as many classes as we'd like, without interfering with the inheritance chain.
-
-## Summary
-
-*Mixin* -- is a generic object-oriented programming term: a class that contains methods for other classes.
-
-Some other languages like e.g. python allow to create mixins using multiple inheritance. JavaScript does not support multiple inheritance, but mixins can be implemented by copying them into the prototype.
-
-We can use mixins as a way to augment a class by multiple behaviors, like event-handling as we have seen above.
-
-Mixins may become a point of conflict if they occasionally overwrite native class methods. So generally one should think well about the naming for a mixin, to minimize such possibility.
diff --git a/1-js/09-classes/08-mixins/head.html b/1-js/09-classes/08-mixins/head.html
deleted file mode 100644
index 77ea38b204..0000000000
--- a/1-js/09-classes/08-mixins/head.html
+++ /dev/null
@@ -1,43 +0,0 @@
-
diff --git a/1-js/09-classes/08-mixins/mixin-inheritance.png b/1-js/09-classes/08-mixins/mixin-inheritance.png
deleted file mode 100644
index 68f9ac2766..0000000000
Binary files a/1-js/09-classes/08-mixins/mixin-inheritance.png and /dev/null differ
diff --git a/1-js/09-classes/08-mixins/mixin-inheritance@2x.png b/1-js/09-classes/08-mixins/mixin-inheritance@2x.png
deleted file mode 100644
index cd3c3004a8..0000000000
Binary files a/1-js/09-classes/08-mixins/mixin-inheritance@2x.png and /dev/null differ
diff --git a/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/solution.md b/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/solution.md
index 05ba72e008..ec0dabc9a6 100644
--- a/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/solution.md
+++ b/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/solution.md
@@ -1,8 +1,8 @@
The difference becomes obvious when we look at the code inside a function.
-The behavior is different if there's a "jump out" of `try..catch`.
+The behavior is different if there's a "jump out" of `try...catch`.
-For instance, when there's a `return` inside `try..catch`. The `finally` clause works in case of *any* exit from `try..catch`, even via the `return` statement: right after `try..catch` is done, but before the calling code gets the control.
+For instance, when there's a `return` inside `try...catch`. The `finally` clause works in case of *any* exit from `try...catch`, even via the `return` statement: right after `try...catch` is done, but before the calling code gets the control.
```js run
function f() {
@@ -11,7 +11,7 @@ function f() {
*!*
return "result";
*/!*
- } catch (e) {
+ } catch (err) {
/// ...
} finally {
alert('cleanup!');
@@ -28,11 +28,11 @@ function f() {
try {
alert('start');
throw new Error("an error");
- } catch (e) {
+ } catch (err) {
// ...
if("can't handle the error") {
*!*
- throw e;
+ throw err;
*/!*
}
@@ -44,4 +44,4 @@ function f() {
f(); // cleanup!
```
-It's `finally` that guarantees the cleanup here. If we just put the code at the end of `f`, it wouldn't run.
+It's `finally` that guarantees the cleanup here. If we just put the code at the end of `f`, it wouldn't run in these situations.
diff --git a/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md b/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md
index e846873438..b6dc813261 100644
--- a/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md
+++ b/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md
@@ -6,12 +6,12 @@ importance: 5
Compare the two code fragments.
-1. The first one uses `finally` to execute the code after `try..catch`:
+1. The first one uses `finally` to execute the code after `try...catch`:
```js
try {
work work
- } catch (e) {
+ } catch (err) {
handle errors
} finally {
*!*
@@ -19,12 +19,12 @@ Compare the two code fragments.
*/!*
}
```
-2. The second fragment puts the cleaning right after `try..catch`:
+2. The second fragment puts the cleaning right after `try...catch`:
```js
try {
work work
- } catch (e) {
+ } catch (err) {
handle errors
}
@@ -33,6 +33,6 @@ Compare the two code fragments.
*/!*
```
-We definitely need the cleanup after the work has started, doesn't matter if there was an error or not.
+We definitely need the cleanup after the work, doesn't matter if there was an error or not.
Is there an advantage here in using `finally` or both code fragments are equal? If there is such an advantage, then give an example when it matters.
diff --git a/1-js/10-error-handling/1-try-catch/article.md b/1-js/10-error-handling/1-try-catch/article.md
index dacc2376be..cad2e1a3e7 100644
--- a/1-js/10-error-handling/1-try-catch/article.md
+++ b/1-js/10-error-handling/1-try-catch/article.md
@@ -1,21 +1,21 @@
-# Error handling, "try..catch"
+# Error handling, "try...catch"
-No matter how great we are at programming, sometimes our scripts have errors. They may occur because of our mistakes, an unexpected user input, an erroneous server response and for a thousand of other reasons.
+No matter how great we are at programming, sometimes our scripts have errors. They may occur because of our mistakes, an unexpected user input, an erroneous server response, and for a thousand other reasons.
Usually, a script "dies" (immediately stops) in case of an error, printing it to console.
-But there's a syntax construct `try..catch` that allows to "catch" errors and, instead of dying, do something more reasonable.
+But there's a syntax construct `try...catch` that allows us to "catch" errors so the script can, instead of dying, do something more reasonable.
-## The "try..catch" syntax
+## The "try...catch" syntax
-The `try..catch` construct has two main blocks: `try`, and then `catch`:
+The `try...catch` construct has two main blocks: `try`, and then `catch`:
```js
try {
// code...
-} catch (err)] {
+} catch (err) {
// error handling
@@ -25,14 +25,14 @@ try {
It works like this:
1. First, the code in `try {...}` is executed.
-2. If there were no errors, then `catch(err)` is ignored: the execution reaches the end of `try` and then jumps over `catch`.
-3. If an error occurs, then `try` execution is stopped, and the control flows to the beginning of `catch(err)`. The `err` variable (can use any name for it) contains an error object with details about what's happened.
+2. If there were no errors, then `catch (err)` is ignored: the execution reaches the end of `try` and goes on, skipping `catch`.
+3. If an error occurs, then the `try` execution is stopped, and control flows to the beginning of `catch (err)`. The `err` variable (we can use any name for it) will contain an error object with details about what happened.
-
+
-So, an error inside the `try {…}` block does not kill the script: we have a chance to handle it in `catch`.
+So, an error inside the `try {...}` block does not kill the script -- we have a chance to handle it in `catch`.
-Let's see more examples.
+Let's look at some examples.
- An errorless example: shows `alert` `(1)` and `(2)`:
@@ -45,13 +45,11 @@ Let's see more examples.
alert('End of try runs'); // *!*(2) <--*/!*
- } catch(err) {
+ } catch (err) {
alert('Catch is ignored, because there are no errors'); // (3)
}
-
- alert("...Then the execution continues");
```
- An example with an error: shows `(1)` and `(3)`:
@@ -66,55 +64,53 @@ Let's see more examples.
alert('End of try (never reached)'); // (2)
- } catch(err) {
+ } catch (err) {
- alert(`Error has occured!`); // *!*(3) <--*/!*
+ alert(`Error has occurred!`); // *!*(3) <--*/!*
}
-
- alert("...Then the execution continues");
```
-````warn header="`try..catch` only works for runtime errors"
-For `try..catch` to work, the code must be runnable. In other words, it should be valid JavaScript.
+````warn header="`try...catch` only works for runtime errors"
+For `try...catch` to work, the code must be runnable. In other words, it should be valid JavaScript.
It won't work if the code is syntactically wrong, for instance it has unmatched curly braces:
```js run
try {
{{{{{{{{{{{{
-} catch(e) {
+} catch (err) {
alert("The engine can't understand this code, it's invalid");
}
```
-The JavaScript engine first reads the code, and then runs it. The errors that occur on the reading phrase are called "parse-time" errors and are unrecoverable (from inside that code). That's because the engine can't understand the code.
+The JavaScript engine first reads the code, and then runs it. The errors that occur on the reading phase are called "parse-time" errors and are unrecoverable (from inside that code). That's because the engine can't understand the code.
-So, `try..catch` can only handle errors that occur in the valid code. Such errors are called "runtime errors" or, sometimes, "exceptions".
+So, `try...catch` can only handle errors that occur in valid code. Such errors are called "runtime errors" or, sometimes, "exceptions".
````
-````warn header="`try..catch` works synchronously"
-If an exception happens in "scheduled" code, like in `setTimeout`, then `try..catch` won't catch it:
+````warn header="`try...catch` works synchronously"
+If an exception happens in "scheduled" code, like in `setTimeout`, then `try...catch` won't catch it:
```js run
try {
setTimeout(function() {
noSuchVariable; // script will die here
}, 1000);
-} catch (e) {
+} catch (err) {
alert( "won't work" );
}
```
-That's because `try..catch` actually wraps the `setTimeout` call that schedules the function. But the function itself is executed later, when the engine has already left the `try..catch` construct.
+That's because the function itself is executed later, when the engine has already left the `try...catch` construct.
-To catch an exception inside a scheduled function, `try..catch` must be inside that function:
+To catch an exception inside a scheduled function, `try...catch` must be inside that function:
```js run
setTimeout(function() {
try {
- noSuchVariable; // try..catch handles the error!
+ noSuchVariable; // try...catch handles the error!
} catch {
alert( "error is caught here!" );
}
@@ -129,15 +125,15 @@ When an error occurs, JavaScript generates an object containing the details abou
```js
try {
// ...
-} catch(err) { // <-- the "error object", could use another word instead of err
+} catch (err) { // <-- the "error object", could use another word instead of err
// ...
}
```
-For all built-in errors, the error object inside `catch` block has two main properties:
+For all built-in errors, the error object has two main properties:
`name`
-: Error name. For an undefined variable that's `"ReferenceError"`.
+: Error name. For instance, for an undefined variable that's `"ReferenceError"`.
`message`
: Textual message about error details.
@@ -154,10 +150,10 @@ try {
*!*
lalala; // error, variable is not defined!
*/!*
-} catch(err) {
+} catch (err) {
alert(err.name); // ReferenceError
alert(err.message); // lalala is not defined
- alert(err.stack); // ReferenceError: lalala is not defined at ...
+ alert(err.stack); // ReferenceError: lalala is not defined at (...call stack)
// Can also show an error as a whole
// The error is converted to string as "name: message"
@@ -174,20 +170,20 @@ If we don't need error details, `catch` may omit it:
```js
try {
// ...
-} catch {
- // error object omitted
+} catch { // <-- without (err)
+ // ...
}
```
-## Using "try..catch"
+## Using "try...catch"
-Let's explore a real-life use case of `try..catch`.
+Let's explore a real-life use case of `try...catch`.
As we already know, JavaScript supports the [JSON.parse(str)](mdn:js/JSON/parse) method to read JSON-encoded values.
Usually it's used to decode data received over the network, from the server or another source.
-We receive it and call `JSON.parse`, like this:
+We receive it and call `JSON.parse` like this:
```js run
let json = '{"name":"John", "age": 30}'; // data from the server
@@ -205,11 +201,11 @@ You can find more detailed information about JSON in the chapter.
**If `json` is malformed, `JSON.parse` generates an error, so the script "dies".**
-Should we be satisfied with that? Of course, not!
+Should we be satisfied with that? Of course not!
This way, if something's wrong with the data, the visitor will never know that (unless they open the developer console). And people really don't like when something "just dies" without any error message.
-Let's use `try..catch` to handle the error:
+Let's use `try...catch` to handle the error:
```js run
let json = "{ bad json }";
@@ -221,12 +217,12 @@ try {
*/!*
alert( user.name ); // doesn't work
-} catch (e) {
+} catch (err) {
*!*
// ...the execution jumps here
alert( "Our apologies, the data has errors, we'll try to request it one more time." );
- alert( e.name );
- alert( e.message );
+ alert( err.name );
+ alert( err.message );
*/!*
}
```
@@ -249,7 +245,7 @@ try {
alert( user.name ); // no name!
*/!*
-} catch (e) {
+} catch (err) {
alert( "doesn't execute" );
}
```
@@ -298,17 +294,17 @@ Let's see what kind of error `JSON.parse` generates:
```js run
try {
JSON.parse("{ bad json o_O }");
-} catch(e) {
+} catch (err) {
*!*
- alert(e.name); // SyntaxError
+ alert(err.name); // SyntaxError
*/!*
- alert(e.message); // Unexpected token o in JSON at position 0
+ alert(err.message); // Unexpected token b in JSON at position 2
}
```
As we can see, that's a `SyntaxError`.
-And in our case, the absence of `name` could be treated as a syntax error also, assuming that users must have a `name`.
+And in our case, the absence of `name` is an error, as users must have a `name`.
So let's throw it:
@@ -327,8 +323,8 @@ try {
alert( user.name );
-} catch(e) {
- alert( "JSON Error: " + e.message ); // JSON Error: Incomplete data: no name
+} catch (err) {
+ alert( "JSON Error: " + err.message ); // JSON Error: Incomplete data: no name
}
```
@@ -338,9 +334,9 @@ Now `catch` became a single place for all error handling: both for `JSON.parse`
## Rethrowing
-In the example above we use `try..catch` to handle incorrect data. But is it possible that *another unexpected error* occurs within the `try {...}` block? Like a variable is undefined or something else, not just that "incorrect data" thing.
+In the example above we use `try...catch` to handle incorrect data. But is it possible that *another unexpected error* occurs within the `try {...}` block? Like a programming error (variable is not defined) or something else, not just this "incorrect data" thing.
-Like this:
+For example:
```js run
let json = '{ "age": 30 }'; // incomplete data
@@ -349,37 +345,41 @@ try {
user = JSON.parse(json); // <-- forgot to put "let" before user
// ...
-} catch(err) {
+} catch (err) {
alert("JSON Error: " + err); // JSON Error: ReferenceError: user is not defined
// (no JSON Error actually)
}
```
-Of course, everything's possible! Programmers do make mistakes. Even in open-source utilities used by millions for decades -- suddenly a crazy bug may be discovered that leads to terrible hacks (like it happened with the `ssh` tool).
+Of course, everything's possible! Programmers do make mistakes. Even in open-source utilities used by millions for decades -- suddenly a bug may be discovered that leads to terrible hacks.
+
+In our case, `try...catch` is placed to catch "incorrect data" errors. But by its nature, `catch` gets *all* errors from `try`. Here it gets an unexpected error, but still shows the same `"JSON Error"` message. That's wrong and also makes the code more difficult to debug.
+
+To avoid such problems, we can employ the "rethrowing" technique. The rule is simple:
+
+**Catch should only process errors that it knows and "rethrow" all others.**
+
+The "rethrowing" technique can be explained in more detail as:
-In our case, `try..catch` is meant to catch "incorrect data" errors. But by its nature, `catch` gets *all* errors from `try`. Here it gets an unexpected error, but still shows the same `"JSON Error"` message. That's wrong and also makes the code more difficult to debug.
+1. Catch gets all errors.
+2. In the `catch (err) {...}` block we analyze the error object `err`.
+3. If we don't know how to handle it, we do `throw err`.
-Fortunately, we can find out which error we get, for instance from its `name`:
+Usually, we can check the error type using the `instanceof` operator:
```js run
try {
user = { /*...*/ };
-} catch(e) {
+} catch (err) {
*!*
- alert(e.name); // "ReferenceError" for accessing an undefined variable
+ if (err instanceof ReferenceError) {
*/!*
+ alert('ReferenceError'); // "ReferenceError" for accessing an undefined variable
+ }
}
```
-The rule is simple:
-
-**Catch should only process errors that it knows and "rethrow" all others.**
-
-The "rethrowing" technique can be explained in more detail as:
-
-1. Catch gets all errors.
-2. In `catch(err) {...}` block we analyze the error object `err`.
-2. If we don't know how to handle it, then we do `throw err`.
+We can also get the error class name from `err.name` property. All native errors have it. Another option is to read `err.constructor.name`.
In the code below, we use rethrowing so that `catch` only handles `SyntaxError`:
@@ -399,24 +399,24 @@ try {
alert( user.name );
-} catch(e) {
+} catch (err) {
*!*
- if (e.name == "SyntaxError") {
- alert( "JSON Error: " + e.message );
+ if (err instanceof SyntaxError) {
+ alert( "JSON Error: " + err.message );
} else {
- throw e; // rethrow (*)
+ throw err; // rethrow (*)
}
*/!*
}
```
-The error throwing on line `(*)` from inside `catch` block "falls out" of `try..catch` and can be either caught by an outer `try..catch` construct (if it exists), or it kills the script.
+The error throwing on line `(*)` from inside `catch` block "falls out" of `try...catch` and can be either caught by an outer `try...catch` construct (if it exists), or it kills the script.
So the `catch` block actually handles only errors that it knows how to deal with and "skips" all others.
-The example below demonstrates how such errors can be caught by one more level of `try..catch`:
+The example below demonstrates how such errors can be caught by one more level of `try...catch`:
```js run
function readData() {
@@ -427,11 +427,11 @@ function readData() {
*!*
blabla(); // error!
*/!*
- } catch (e) {
+ } catch (err) {
// ...
- if (e.name != 'SyntaxError') {
+ if (!(err instanceof SyntaxError)) {
*!*
- throw e; // rethrow (don't know how to deal with it)
+ throw err; // rethrow (don't know how to deal with it)
*/!*
}
}
@@ -439,20 +439,20 @@ function readData() {
try {
readData();
-} catch (e) {
+} catch (err) {
*!*
- alert( "External catch got: " + e ); // caught it!
+ alert( "External catch got: " + err ); // caught it!
*/!*
}
```
-Here `readData` only knows how to handle `SyntaxError`, while the outer `try..catch` knows how to handle everything.
+Here `readData` only knows how to handle `SyntaxError`, while the outer `try...catch` knows how to handle everything.
-## try..catch..finally
+## try...catch...finally
Wait, that's not all.
-The `try..catch` construct may have one more code clause: `finally`.
+The `try...catch` construct may have one more code clause: `finally`.
If it exists, it runs in all cases:
@@ -464,7 +464,7 @@ The extended syntax looks like this:
```js
*!*try*/!* {
... try to execute the code ...
-} *!*catch*/!*(e) {
+} *!*catch*/!* (err) {
... handle errors ...
} *!*finally*/!* {
... execute always ...
@@ -477,7 +477,7 @@ Try running this code:
try {
alert( 'try' );
if (confirm('Make an error?')) BAD_CODE();
-} catch (e) {
+} catch (err) {
alert( 'catch' );
} finally {
alert( 'finally' );
@@ -489,7 +489,7 @@ The code has two ways of execution:
1. If you answer "Yes" to "Make an error?", then `try -> catch -> finally`.
2. If you say "No", then `try -> finally`.
-The `finally` clause is often used when we start doing something before `try..catch` and want to finalize it in any case of outcome.
+The `finally` clause is often used when we start doing something and want to finalize it in any case of outcome.
For instance, we want to measure the time that a Fibonacci numbers function `fib(n)` takes. Naturally, we can start measuring before it runs and finish afterwards. But what if there's an error during the function call? In particular, the implementation of `fib(n)` in the code below returns an error for negative or non-integer numbers.
@@ -513,7 +513,7 @@ let start = Date.now();
try {
result = fib(num);
-} catch (e) {
+} catch (err) {
result = 0;
*!*
} finally {
@@ -521,24 +521,24 @@ try {
}
*/!*
-alert(result || "error occured");
+alert(result || "error occurred");
alert( `execution took ${diff}ms` );
```
-You can check by running the code with entering `35` into `prompt` -- it executes normally, `finally` after `try`. And then enter `-1` -- there will be an immediate error, an the execution will take `0ms`. Both measurements are done correctly.
+You can check by running the code with entering `35` into `prompt` -- it executes normally, `finally` after `try`. And then enter `-1` -- there will be an immediate error, and the execution will take `0ms`. Both measurements are done correctly.
-In other words, there may be two ways to exit a function: either a `return` or `throw`. The `finally` clause handles them both.
+In other words, the function may finish with `return` or `throw`, that doesn't matter. The `finally` clause executes in both cases.
-```smart header="Variables are local inside `try..catch..finally`"
-Please note that `result` and `diff` variables in the code above are declared *before* `try..catch`.
+```smart header="Variables are local inside `try...catch...finally`"
+Please note that `result` and `diff` variables in the code above are declared *before* `try...catch`.
-Otherwise, if `let` were made inside the `{...}` block, it would only be visible inside of it.
+Otherwise, if we declared `let` in `try` block, it would only be visible inside of it.
```
````smart header="`finally` and `return`"
-The `finally` clause works for *any* exit from `try..catch`. That includes an explicit `return`.
+The `finally` clause works for *any* exit from `try...catch`. That includes an explicit `return`.
In the example below, there's a `return` in `try`. In this case, `finally` is executed just before the control returns to the outer code.
@@ -550,7 +550,7 @@ function func() {
return 1;
*/!*
- } catch (e) {
+ } catch (err) {
/* ... */
} finally {
*!*
@@ -563,9 +563,9 @@ alert( func() ); // first works alert from finally, and then this one
```
````
-````smart header="`try..finally`"
+````smart header="`try...finally`"
-The `try..finally` construct, without `catch` clause, is also useful. We apply it when we don't want to handle errors right here, but want to be sure that processes that we started are finalized.
+The `try...finally` construct, without `catch` clause, is also useful. We apply it when we don't want to handle errors here (let them fall through), but want to be sure that processes that we started are finalized.
```js
function func() {
@@ -577,7 +577,7 @@ function func() {
}
}
```
-In the code above, an error inside `try` always falls out, because there's no `catch`. But `finally` works before the execution flow jumps outside.
+In the code above, an error inside `try` always falls out, because there's no `catch`. But `finally` works before the execution flow leaves the function.
````
## Global catch
@@ -586,11 +586,11 @@ In the code above, an error inside `try` always falls out, because there's no `c
The information from this section is not a part of the core JavaScript.
```
-Let's imagine we've got a fatal error outside of `try..catch`, and the script died. Like a programming error or something else terrible.
+Let's imagine we've got a fatal error outside of `try...catch`, and the script died. Like a programming error or some other terrible thing.
-Is there a way to react on such occurrences? We may want to log the error, show something to the user (normally they don't see error messages) etc.
+Is there a way to react on such occurrences? We may want to log the error, show something to the user (normally they don't see error messages), etc.
-There is none in the specification, but environments usually provide it, because it's really useful. For instance, Node.JS has [process.on('uncaughtException')](https://nodejs.org/api/process.html#process_event_uncaughtexception) for that. And in the browser we can assign a function to special [window.onerror](mdn:api/GlobalEventHandlers/onerror) property. It will run in case of an uncaught error.
+There is none in the specification, but environments usually provide it, because it's really useful. For instance, Node.js has [`process.on("uncaughtException")`](https://nodejs.org/api/process.html#process_event_uncaughtexception) for that. And in the browser we can assign a function to the special [window.onerror](mdn:api/GlobalEventHandlers/onerror) property, that will run in case of an uncaught error.
The syntax:
@@ -632,25 +632,25 @@ For instance:
The role of the global handler `window.onerror` is usually not to recover the script execution -- that's probably impossible in case of programming errors, but to send the error message to developers.
-There are also web-services that provide error-logging for such cases, like or .
+There are also web-services that provide error-logging for such cases, like or .
They work like this:
1. We register at the service and get a piece of JS (or a script URL) from them to insert on pages.
-2. That JS script has a custom `window.onerror` function.
+2. That JS script sets a custom `window.onerror` function.
3. When an error occurs, it sends a network request about it to the service.
4. We can log in to the service web interface and see errors.
## Summary
-The `try..catch` construct allows to handle runtime errors. It literally allows to try running the code and catch errors that may occur in it.
+The `try...catch` construct allows to handle runtime errors. It literally allows to "try" running the code and "catch" errors that may occur in it.
The syntax is:
```js
try {
// run this code
-} catch(err) {
+} catch (err) {
// if an error happened, then jump here
// err is the error object
} finally {
@@ -658,18 +658,18 @@ try {
}
```
-There may be no `catch` section or no `finally`, so `try..catch` and `try..finally` are also valid.
+There may be no `catch` section or no `finally`, so shorter constructs `try...catch` and `try...finally` are also valid.
Error objects have following properties:
- `message` -- the human-readable error message.
- `name` -- the string with error name (error constructor name).
-- `stack` (non-standard) -- the stack at the moment of error creation.
+- `stack` (non-standard, but well-supported) -- the stack at the moment of error creation.
-If error is not needed, we can omit it by using `catch {` instead of `catch(err) {`.
+If an error object is not needed, we can omit it by using `catch {` instead of `catch (err) {`.
We can also generate our own errors using the `throw` operator. Technically, the argument of `throw` can be anything, but usually it's an error object inheriting from the built-in `Error` class. More on extending errors in the next chapter.
-Rethrowing is a basic pattern of error handling: a `catch` block usually expects and knows how to handle the particular error type, so it should rethrow errors it doesn't know.
+*Rethrowing* is a very important pattern of error handling: a `catch` block usually expects and knows how to handle the particular error type, so it should rethrow errors it doesn't know.
-Even if we don't have `try..catch`, most environments allow to setup a "global" error handler to catch errors that "fall out". In-browser that's `window.onerror`.
+Even if we don't have `try...catch`, most environments allow us to setup a "global" error handler to catch errors that "fall out". In-browser, that's `window.onerror`.
diff --git a/1-js/10-error-handling/1-try-catch/try-catch-flow.png b/1-js/10-error-handling/1-try-catch/try-catch-flow.png
deleted file mode 100644
index 92182950b1..0000000000
Binary files a/1-js/10-error-handling/1-try-catch/try-catch-flow.png and /dev/null differ
diff --git a/1-js/10-error-handling/1-try-catch/try-catch-flow.svg b/1-js/10-error-handling/1-try-catch/try-catch-flow.svg
new file mode 100644
index 0000000000..2c0d71348c
--- /dev/null
+++ b/1-js/10-error-handling/1-try-catch/try-catch-flow.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/10-error-handling/1-try-catch/try-catch-flow@2x.png b/1-js/10-error-handling/1-try-catch/try-catch-flow@2x.png
deleted file mode 100644
index 7515aa8c12..0000000000
Binary files a/1-js/10-error-handling/1-try-catch/try-catch-flow@2x.png and /dev/null differ
diff --git a/1-js/10-error-handling/2-custom-errors/1-format-error/solution.md b/1-js/10-error-handling/2-custom-errors/1-format-error/solution.md
index bb6b74cfaf..754e68f9a4 100644
--- a/1-js/10-error-handling/2-custom-errors/1-format-error/solution.md
+++ b/1-js/10-error-handling/2-custom-errors/1-format-error/solution.md
@@ -2,7 +2,7 @@
class FormatError extends SyntaxError {
constructor(message) {
super(message);
- this.name = "FormatError";
+ this.name = this.constructor.name;
}
}
diff --git a/1-js/10-error-handling/2-custom-errors/article.md b/1-js/10-error-handling/2-custom-errors/article.md
index 5079c746d3..d28b07439b 100644
--- a/1-js/10-error-handling/2-custom-errors/article.md
+++ b/1-js/10-error-handling/2-custom-errors/article.md
@@ -2,11 +2,11 @@
When we develop something, we often need our own error classes to reflect specific things that may go wrong in our tasks. For errors in network operations we may need `HttpError`, for database operations `DbError`, for searching operations `NotFoundError` and so on.
-Our errors should support basic error properties like `message`, `name` and, preferably, `stack`. But they also may have other properties of their own, e.g. `HttpError` objects may have `statusCode` property with a value like `404` or `403` or `500`.
+Our errors should support basic error properties like `message`, `name` and, preferably, `stack`. But they also may have other properties of their own, e.g. `HttpError` objects may have a `statusCode` property with a value like `404` or `403` or `500`.
JavaScript allows to use `throw` with any argument, so technically our custom error classes don't need to inherit from `Error`. But if we inherit, then it becomes possible to use `obj instanceof Error` to identify error objects. So it's better to inherit from it.
-As we build our application, our own errors naturally form a hierarchy, for instance `HttpTimeoutError` may inherit from `HttpError`, and so on.
+As the application grows, our own errors naturally form a hierarchy. For instance, `HttpTimeoutError` may inherit from `HttpError`, and so on.
## Extending Error
@@ -17,17 +17,13 @@ Here's an example of how a valid `json` may look:
let json = `{ "name": "John", "age": 30 }`;
```
-Internally, we'll use `JSON.parse`. If it receives malformed `json`, then it throws `SyntaxError`.
-
-But even if `json` is syntactically correct, that doesn't mean that it's a valid user, right? It may miss the necessary data. For instance, it may not have `name` and `age` properties that are essential for our users.
+Internally, we'll use `JSON.parse`. If it receives malformed `json`, then it throws `SyntaxError`. But even if `json` is syntactically correct, that doesn't mean that it's a valid user, right? It may miss the necessary data. For instance, it may not have `name` and `age` properties that are essential for our users.
Our function `readUser(json)` will not only read JSON, but check ("validate") the data. If there are no required fields, or the format is wrong, then that's an error. And that's not a `SyntaxError`, because the data is syntactically correct, but another kind of error. We'll call it `ValidationError` and create a class for it. An error of that kind should also carry the information about the offending field.
-Our `ValidationError` class should inherit from the built-in `Error` class.
-
-That class is built-in, but we should have its approximate code before our eyes, to understand what we're extending.
+Our `ValidationError` class should inherit from the `Error` class.
-So here you are:
+The `Error` class is built-in, but here's its approximate code so we can understand what we're extending:
```js
// The "pseudocode" for the built-in Error class defined by JavaScript itself
@@ -35,14 +31,14 @@ class Error {
constructor(message) {
this.message = message;
this.name = "Error"; // (different names for different built-in error classes)
- this.stack = ; // non-standard, but most environments support it
+ this.stack = ; // non-standard, but most environments support it
}
}
```
-Now let's go on and inherit `ValidationError` from it:
+Now let's inherit `ValidationError` from it and try it in action:
-```js run untrusted
+```js run
*!*
class ValidationError extends Error {
*/!*
@@ -65,10 +61,9 @@ try {
}
```
-Please take a look at the constructor:
+Please note: in the line `(1)` we call the parent constructor. JavaScript requires us to call `super` in the child constructor, so that's obligatory. The parent constructor sets the `message` property.
-1. In the line `(1)` we call the parent constructor. JavaScript requires us to call `super` in the child constructor, so that's obligatory. The parent constructor sets the `message` property.
-2. The parent constructor also sets the `name` property to `"Error"`, so in the line `(2)` we reset it to the right value.
+The parent constructor also sets the `name` property to `"Error"`, so in the line `(2)` we reset it to the right value.
Let's try to use it in `readUser(json)`:
@@ -122,15 +117,15 @@ We could also look at `err.name`, like this:
// instead of (err instanceof SyntaxError)
} else if (err.name == "SyntaxError") { // (*)
// ...
-```
+```
The `instanceof` version is much better, because in the future we are going to extend `ValidationError`, make subtypes of it, like `PropertyRequiredError`. And `instanceof` check will continue to work for new inheriting classes. So that's future-proof.
-Also it's important that if `catch` meets an unknown error, then it rethrows it in the line `(**)`. The `catch` only knows how to handle validation and syntax errors, other kinds (due to a typo in the code or such) should fall through.
+Also it's important that if `catch` meets an unknown error, then it rethrows it in the line `(**)`. The `catch` block only knows how to handle validation and syntax errors, other kinds (caused by a typo in the code or other unknown reasons) should fall through.
## Further inheritance
-The `ValidationError` class is very generic. Many things may go wrong. The property may be absent or it may be in a wrong format (like a string value for `age`). Let's make a more concrete class `PropertyRequiredError`, exactly for absent properties. It will carry additional information about the property that's missing.
+The `ValidationError` class is very generic. Many things may go wrong. The property may be absent or it may be in a wrong format (like a string value for `age` instead of a number). Let's make a more concrete class `PropertyRequiredError`, exactly for absent properties. It will carry additional information about the property that's missing.
```js run
class ValidationError extends Error {
@@ -185,7 +180,7 @@ try {
The new class `PropertyRequiredError` is easy to use: we only need to pass the property name: `new PropertyRequiredError(property)`. The human-readable `message` is generated by the constructor.
-Please note that `this.name` in `PropertyRequiredError` constructor is again assigned manually. That may become a bit tedious -- to assign `this.name = ` when creating each custom error. But there's a way out. We can make our own "basic error" class that removes this burden from our shoulders by using `this.constructor.name` for `this.name` in the constructor. And then inherit from it.
+Please note that `this.name` in `PropertyRequiredError` constructor is again assigned manually. That may become a bit tedious -- to assign `this.name = ` in every custom error class. We can avoid it by making our own "basic error" class that assigns `this.name = this.constructor.name`. And then inherit all our custom errors from it.
Let's call it `MyError`.
@@ -218,13 +213,41 @@ Now custom errors are much shorter, especially `ValidationError`, as we got rid
## Wrapping exceptions
-The purpose of the function `readUser` in the code above is "to read the user data", right? There may occur different kinds of errors in the process. Right now we have `SyntaxError` and `ValidationError`, but in the future `readUser` function may grow: the new code will probably generate other kinds of errors.
+The purpose of the function `readUser` in the code above is "to read the user data". There may occur different kinds of errors in the process. Right now we have `SyntaxError` and `ValidationError`, but in the future `readUser` function may grow and probably generate other kinds of errors.
+
+The code which calls `readUser` should handle these errors. Right now it uses multiple `if`s in the `catch` block, that check the class and handle known errors and rethrow the unknown ones.
+
+The scheme is like this:
+
+```js
+try {
+ ...
+ readUser() // the potential error source
+ ...
+} catch (err) {
+ if (err instanceof ValidationError) {
+ // handle validation errors
+ } else if (err instanceof SyntaxError) {
+ // handle syntax errors
+ } else {
+ throw err; // unknown error, rethrow it
+ }
+}
+```
+
+In the code above we can see two types of errors, but there can be more.
+
+If the `readUser` function generates several kinds of errors, then we should ask ourselves: do we really want to check for all error types one-by-one every time?
+
+Often the answer is "No": we'd like to be "one level above all that". We just want to know if there was a "data reading error" -- why exactly it happened is often irrelevant (the error message describes it). Or, even better, we'd like to have a way to get the error details, but only if we need to.
-The code which calls `readUser` should handle these errors. Right now it uses multiple `if` in the `catch` block to check for different error types and rethrow the unknown ones. But if `readUser` function generates several kinds of errors -- then we should ask ourselves: do we really want to check for all error types one-by-one in every code that calls `readUser`?
+The technique that we describe here is called "wrapping exceptions".
-Often the answer is "No": the outer code wants to be "one level above all that". It wants to have some kind of "data reading error". Why exactly it happened -- is often irrelevant (the error message describes it). Or, even better if there is a way to get error details, but only if we need to.
+1. We'll make a new class `ReadError` to represent a generic "data reading" error.
+2. The function `readUser` will catch data reading errors that occur inside it, such as `ValidationError` and `SyntaxError`, and generate a `ReadError` instead.
+3. The `ReadError` object will keep the reference to the original error in its `cause` property.
-So let's make a new class `ReadError` to represent such errors. If an error occurs inside `readUser`, we'll catch it there and generate `ReadError`. We'll also keep the reference to the original error in its `cause` property. Then the outer code will only have to check for `ReadError`.
+Then the code that calls `readUser` will only have to check for `ReadError`, not for every kind of data reading errors. And if it needs more details of an error, it can check its `cause` property.
Here's the code that defines `ReadError` and demonstrates its use in `readUser` and `try..catch`:
@@ -296,12 +319,12 @@ try {
In the code above, `readUser` works exactly as described -- catches syntax and validation errors and throws `ReadError` errors instead (unknown errors are rethrown as usual).
-So the outer code checks `instanceof ReadError` and that's it. No need to list possible all error types.
+So the outer code checks `instanceof ReadError` and that's it. No need to list all possible error types.
-The approach is called "wrapping exceptions", because we take "low level exceptions" and "wrap" them into `ReadError` that is more abstract and more convenient to use for the calling code. It is widely used in object-oriented programming.
+The approach is called "wrapping exceptions", because we take "low level" exceptions and "wrap" them into `ReadError` that is more abstract. It is widely used in object-oriented programming.
## Summary
-- We can inherit from `Error` and other built-in error classes normally, just need to take care of `name` property and don't forget to call `super`.
-- Most of the time, we should use `instanceof` to check for particular errors. It also works with inheritance. But sometimes we have an error object coming from the 3rd-party library and there's no easy way to get the class. Then `name` property can be used for such checks.
-- Wrapping exceptions is a widespread technique when a function handles low-level exceptions and makes a higher-level object to report about the errors. Low-level exceptions sometimes become properties of that object like `err.cause` in the examples above, but that's not strictly required.
+- We can inherit from `Error` and other built-in error classes normally. We just need to take care of the `name` property and don't forget to call `super`.
+- We can use `instanceof` to check for particular errors. It also works with inheritance. But sometimes we have an error object coming from a 3rd-party library and there's no easy way to get its class. Then `name` property can be used for such checks.
+- Wrapping exceptions is a widespread technique: a function handles low-level exceptions and creates higher-level errors instead of various low-level ones. Low-level exceptions sometimes become properties of that object like `err.cause` in the examples above, but that's not strictly required.
diff --git a/1-js/11-async/01-callbacks/01-animate-circle-callback/solution.view/index.html b/1-js/11-async/01-callbacks/01-animate-circle-callback/solution.view/index.html
deleted file mode 100644
index b2192681c9..0000000000
--- a/1-js/11-async/01-callbacks/01-animate-circle-callback/solution.view/index.html
+++ /dev/null
@@ -1,59 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/1-js/11-async/01-callbacks/article.md b/1-js/11-async/01-callbacks/article.md
index a5a91793e8..57115a9098 100644
--- a/1-js/11-async/01-callbacks/article.md
+++ b/1-js/11-async/01-callbacks/article.md
@@ -2,38 +2,53 @@
# Introduction: callbacks
-Many actions in JavaScript are *asynchronous*.
+```warn header="We use browser methods in examples here"
+To demonstrate the use of callbacks, promises and other abstract concepts, we'll be using some browser methods: specifically, loading scripts and performing simple document manipulations.
-For instance, take a look at the function `loadScript(src)`:
+If you're not familiar with these methods, and their usage in the examples is confusing, you may want to read a few chapters from the [next part](/document) of the tutorial.
+
+Although, we'll try to make things clear anyway. There won't be anything really complex browser-wise.
+```
+
+Many functions are provided by JavaScript host environments that allow you to schedule *asynchronous* actions. In other words, actions that we initiate now, but they finish later.
+
+For instance, one such function is the `setTimeout` function.
+
+There are other real-world examples of asynchronous actions, e.g. loading scripts and modules (we'll cover them in later chapters).
+
+Take a look at the function `loadScript(src)`, that loads a script with the given `src`:
```js
function loadScript(src) {
+ // creates a
return valuereturn promisethrow errorstate: "fulfilled"result: valuestate: "rejected"result: error...with the resultof the new promise...state: "pending"result: undefinedthe call of .then(handler) always returns a promise:if handler ends with…that promise settles with:
\ No newline at end of file
diff --git a/1-js/11-async/03-promise-chaining/promise-handler-variants@2x.png b/1-js/11-async/03-promise-chaining/promise-handler-variants@2x.png
deleted file mode 100644
index 98d0fa46bc..0000000000
Binary files a/1-js/11-async/03-promise-chaining/promise-handler-variants@2x.png and /dev/null differ
diff --git a/1-js/11-async/03-promise-chaining/promise-then-chain.png b/1-js/11-async/03-promise-chaining/promise-then-chain.png
deleted file mode 100644
index 52939e5fdf..0000000000
Binary files a/1-js/11-async/03-promise-chaining/promise-then-chain.png and /dev/null differ
diff --git a/1-js/11-async/03-promise-chaining/promise-then-chain.svg b/1-js/11-async/03-promise-chaining/promise-then-chain.svg
new file mode 100644
index 0000000000..fb60142fbd
--- /dev/null
+++ b/1-js/11-async/03-promise-chaining/promise-then-chain.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/11-async/03-promise-chaining/promise-then-chain@2x.png b/1-js/11-async/03-promise-chaining/promise-then-chain@2x.png
deleted file mode 100644
index 731f8c93c3..0000000000
Binary files a/1-js/11-async/03-promise-chaining/promise-then-chain@2x.png and /dev/null differ
diff --git a/1-js/11-async/03-promise-chaining/promise-then-many.png b/1-js/11-async/03-promise-chaining/promise-then-many.png
deleted file mode 100644
index c37f6fe010..0000000000
Binary files a/1-js/11-async/03-promise-chaining/promise-then-many.png and /dev/null differ
diff --git a/1-js/11-async/03-promise-chaining/promise-then-many.svg b/1-js/11-async/03-promise-chaining/promise-then-many.svg
new file mode 100644
index 0000000000..8fea7beaaf
--- /dev/null
+++ b/1-js/11-async/03-promise-chaining/promise-then-many.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/11-async/03-promise-chaining/promise-then-many@2x.png b/1-js/11-async/03-promise-chaining/promise-then-many@2x.png
deleted file mode 100644
index 6fc13c2c67..0000000000
Binary files a/1-js/11-async/03-promise-chaining/promise-then-many@2x.png and /dev/null differ
diff --git a/1-js/11-async/04-promise-error-handling/article.md b/1-js/11-async/04-promise-error-handling/article.md
index 6a0c64c042..c5b4206ab2 100644
--- a/1-js/11-async/04-promise-error-handling/article.md
+++ b/1-js/11-async/04-promise-error-handling/article.md
@@ -1,11 +1,9 @@
# Error handling with promises
-Asynchronous actions may sometimes fail: in case of an error the corresponding promise becomes rejected. For instance, `fetch` fails if the remote server is not available. We can use `.catch` to handle errors (rejections).
+Promise chains are great at error handling. When a promise rejects, the control jumps to the closest rejection handler. That's very convenient in practice.
-Promise chaining is great at that aspect. When a promise rejects, the control jumps to the closest rejection handler down the chain. That's very convenient in practice.
-
-For instance, in the code below the URL is wrong (no such server) and `.catch` handles the error:
+For instance, in the code below the URL to `fetch` is wrong (no such site) and `.catch` handles the error:
```js run
*!*
@@ -15,17 +13,9 @@ fetch('https://github.com/service/https://no-such-server.blabla/') // rejects
.catch(err => alert(err)) // TypeError: failed to fetch (the text may vary)
```
-Or, maybe, everything is all right with the server, but the response is not a valid JSON:
+As you can see, the `.catch` doesn't have to be immediate. It may appear after one or maybe several `.then`.
-```js run
-fetch('https://github.com/') // fetch works fine now, the server responds successfully
-*!*
- .then(response => response.json()) // rejects: the page is HTML, not a valid json
-*/!*
- .catch(err => alert(err)) // SyntaxError: Unexpected token < in JSON at position 0
-```
-
-The easiest way to catch all errors is to append `.catch` to the end of chain:
+Or, maybe, everything is all right with the site, but the response is not valid JSON. The easiest way to catch all errors is to append `.catch` to the end of chain:
```js run
fetch('https://github.com/article/promise-chaining/user.json')
@@ -48,11 +38,11 @@ fetch('https://github.com/article/promise-chaining/user.json')
*/!*
```
-Normally, `.catch` doesn't trigger at all, because there are no errors. But if any of the promises above rejects (a network problem or invalid json or whatever), then it would catch it.
+Normally, such `.catch` doesn't trigger at all. But if any of the promises above rejects (a network problem or invalid json or whatever), then it would catch it.
## Implicit try..catch
-The code of a promise executor and promise handlers has an "invisible `try..catch`" around it. If an error happens, it gets caught and treated as a rejection.
+The code of a promise executor and promise handlers has an "invisible `try..catch`" around it. If an exception happens, it gets caught and treated as a rejection.
For instance, this code:
@@ -70,13 +60,13 @@ new Promise((resolve, reject) => {
new Promise((resolve, reject) => {
*!*
reject(new Error("Whoops!"));
-*/!*
+*/!*
}).catch(alert); // Error: Whoops!
```
-The "invisible `try..catch`" around the executor automatically catches the error and treats it as a rejection.
+The "invisible `try..catch`" around the executor automatically catches the error and turns it into rejected promise.
-That's so not only in the executor, but in handlers as well. If we `throw` inside `.then` handler, that means a rejected promise, so the control jumps to the nearest error handler.
+This happens not only in the executor function, but in its handlers as well. If we `throw` inside a `.then` handler, that means a rejected promise, so the control jumps to the nearest error handler.
Here's an example:
@@ -90,7 +80,7 @@ new Promise((resolve, reject) => {
}).catch(alert); // Error: Whoops!
```
-That's so not only for `throw`, but for any errors, including programming errors as well:
+This happens for all errors, not just those caused by the `throw` statement. For example, a programming error:
```js run
new Promise((resolve, reject) => {
@@ -102,15 +92,15 @@ new Promise((resolve, reject) => {
}).catch(alert); // ReferenceError: blabla is not defined
```
-As a side effect, the final `.catch` not only catches explicit rejections, but also occasional errors in the handlers above.
+The final `.catch` not only catches explicit rejections, but also accidental errors in the handlers above.
## Rethrowing
-As we already noticed, `.catch` behaves like `try..catch`. We may have as many `.then` as we want, and then use a single `.catch` at the end to handle errors in all of them.
+As we already noticed, `.catch` at the end of the chain is similar to `try..catch`. We may have as many `.then` handlers as we want, and then use a single `.catch` at the end to handle errors in all of them.
-In a regular `try..catch` we can analyze the error and maybe rethrow it if can't handle. The same thing is possible for promises.
+In a regular `try..catch` we can analyze the error and maybe rethrow it if it can't be handled. The same thing is possible for promises.
-If we `throw` inside `.catch`, then the control goes to the next closest error handler. And if we handle the error and finish normally, then it continues to the closest successful `.then` handler.
+If we `throw` inside `.catch`, then the control goes to the next closest error handler. And if we handle the error and finish normally, then it continues to the next closest successful `.then` handler.
In the example below the `.catch` successfully handles the error:
@@ -132,7 +122,7 @@ Here the `.catch` block finishes normally. So the next successful `.then` handle
In the example below we see the other situation with `.catch`. The handler `(*)` catches the error and just can't handle it (e.g. it only knows how to handle `URIError`), so it throws it again:
```js run
-// the execution: catch -> catch -> then
+// the execution: catch -> catch
new Promise((resolve, reject) => {
throw new Error("Whoops!");
@@ -150,7 +140,7 @@ new Promise((resolve, reject) => {
}
}).then(function() {
- /* never runs here */
+ /* doesn't run here */
}).catch(error => { // (**)
alert(`The unknown error has occurred: ${error}`);
@@ -159,116 +149,28 @@ new Promise((resolve, reject) => {
});
```
-Then the execution jumps from the first `.catch` `(*)` to the next one `(**)` down the chain.
-
-In the section below we'll see a practical example of rethrowing.
-
-## Fetch error handling example
-
-Let's improve error handling for the user-loading example.
-
-The promise returned by [fetch](mdn:api/WindowOrWorkerGlobalScope/fetch) rejects when it's impossible to make a request. For instance, a remote server is not available, or the URL is malformed. But if the remote server responds with error 404, or even error 500, then it's considered a valid response.
-
-What if the server returns a non-JSON page with error 500 in the line `(*)`? What if there's no such user, and github returns a page with error 404 at `(**)`?
-
-```js run
-fetch('https://github.com/no-such-user.json') // (*)
- .then(response => response.json())
- .then(user => fetch(`https://api.github.com/users/${user.name}`)) // (**)
- .then(response => response.json())
- .catch(alert); // SyntaxError: Unexpected token < in JSON at position 0
- // ...
-```
-
-
-As of now, the code tries to load the response as JSON no matter what and dies with a syntax error. You can see that by running the example above, as the file `no-such-user.json` doesn't exist.
-
-That's not good, because the error just falls through the chain, without details: what failed and where.
-
-So let's add one more step: we should check the `response.status` property that has HTTP status, and if it's not 200, then throw an error.
-
-```js run
-class HttpError extends Error { // (1)
- constructor(response) {
- super(`${response.status} for ${response.url}`);
- this.name = 'HttpError';
- this.response = response;
- }
-}
-
-function loadJson(url) { // (2)
- return fetch(url)
- .then(response => {
- if (response.status == 200) {
- return response.json();
- } else {
- throw new HttpError(response);
- }
- })
-}
-
-loadJson('no-such-user.json') // (3)
- .catch(alert); // HttpError: 404 for .../no-such-user.json
-```
-
-1. We make a custom class for HTTP Errors to distinguish them from other types of errors. Besides, the new class has a constructor that accepts `response` object and saves it in the error. So error-handling code will be able to access it.
-2. Then we put together the requesting and error-handling code into a function that fetches the `url` *and* treats any non-200 status as an error. That's convenient, because we often need such logic.
-3. Now `alert` shows better message.
-
-The great thing about having our own class for errors is that we can easily check for it in error-handling code.
-
-For instance, we can make a request, and then if we get 404 -- ask the user to modify the information.
-
-The code below loads a user with the given name from github. If there's no such user, then it asks for the correct name:
-
-```js run
-function demoGithubUser() {
- let name = prompt("Enter a name?", "iliakan");
-
- return loadJson(`https://api.github.com/users/${name}`)
- .then(user => {
- alert(`Full name: ${user.name}.`);
- return user;
- })
- .catch(err => {
-*!*
- if (err instanceof HttpError && err.response.status == 404) {
-*/!*
- alert("No such user, please reenter.");
- return demoGithubUser();
- } else {
- throw err; // (*)
- }
- });
-}
-
-demoGithubUser();
-```
-
-Please note: `.catch` here catches all errors, but it "knows how to handle" only `HttpError 404`. In that particular case it means that there's no such user, and `.catch` just retries in that case.
-
-For other errors, it has no idea what could go wrong. Maybe a programming error or something. So it just rethrows it in the line `(*)`.
+The execution jumps from the first `.catch` `(*)` to the next one `(**)` down the chain.
## Unhandled rejections
-What happens when an error is not handled? For instance, after the rethrow `(*)` in the example above.
-
-Or we could just forget to append an error handler to the end of the chain, like here:
+What happens when an error is not handled? For instance, we forgot to append `.catch` to the end of the chain, like here:
```js untrusted run refresh
new Promise(function() {
noSuchFunction(); // Error here (no such function)
})
.then(() => {
- // zero or many promise handlers
+ // successful promise handlers, one or more
}); // without .catch at the end!
```
-In case of an error, the promise state becomes "rejected", and the execution should jump to the closest rejection handler. But there is no such handler in the examples above. So the error gets "stuck".
+In case of an error, the promise becomes rejected, and the execution should jump to the closest rejection handler. But there is none. So the error gets "stuck". There's no code to handle it.
+
+In practice, just like with regular unhandled errors in code, it means that something has gone terribly wrong.
-In practice, just like with a regular unhandled errors, it means that something terribly gone wrong, the script probably died.
+What happens when a regular error occurs and is not caught by `try..catch`? The script dies with a message in the console. A similar thing happens with unhandled promise rejections.
-Most JavaScript engines track such situations and generate a global error in that case. We can see it in the console.
+The JavaScript engine tracks such rejections and generates a global error in that case. You can see it in the console if you run the example above.
In the browser we can catch such errors using the event `unhandledrejection`:
@@ -292,52 +194,12 @@ If an error occurs, and there's no `.catch`, the `unhandledrejection` handler tr
Usually such errors are unrecoverable, so our best way out is to inform the user about the problem and probably report the incident to the server.
-In non-browser environments like Node.JS there are other similar ways to track unhandled errors.
-
+In non-browser environments like Node.js there are other ways to track unhandled errors.
## Summary
-- `.catch` handles promise rejections of all kinds: be it a `reject()` call, or an error thrown in a handler.
-- We should place `.catch` exactly in places where we want to handle errors and know how to handle them. The handler should analyze errors (custom error classes help) and rethrow unknown ones.
-- It's normal not to use `.catch` if we don't know how to handle errors (all errors are unrecoverable).
-- In any case we should have the `unhandledrejection` event handler (for browsers, and analogs for other environments), to track unhandled errors and inform the user (and probably our server) about the them. So that our app never "just dies".
-
-And finally, if we have load-indication, then `.finally` is a great handler to stop it when the fetch is complete:
-
-```js run
-function demoGithubUser() {
- let name = prompt("Enter a name?", "iliakan");
-
-*!*
- document.body.style.opacity = 0.3; // (1) start the indication
-*/!*
-
- return loadJson(`https://api.github.com/users/${name}`)
-*!*
- .finally(() => { // (2) stop the indication
- document.body.style.opacity = '';
- return new Promise(resolve => setTimeout(resolve, 0)); // (*)
- })
-*/!*
- .then(user => {
- alert(`Full name: ${user.name}.`);
- return user;
- })
- .catch(err => {
- if (err instanceof HttpError && err.response.status == 404) {
- alert("No such user, please reenter.");
- return demoGithubUser();
- } else {
- throw err;
- }
- });
-}
-
-demoGithubUser();
-```
-
-Here on the line `(1)` we indicate loading by dimming the document. The method doesn't matter, could use any type of indication instead.
-
-When the promise is settled, be it a successful fetch or an error, `finally` triggers at the line `(2)` and stops the indication.
-
-There's a little browser trick `(*)` with returning a zero-timeout promise from `finally`. That's because some browsers (like Chrome) need "a bit time" outside promise handlers to paint document changes. So it ensures that the indication is visually stopped before going further on the chain.
+- `.catch` handles errors in promises of all kinds: be it a `reject()` call, or an error thrown in a handler.
+- `.then` also catches errors in the same manner, if given the second argument (which is the error handler).
+- We should place `.catch` exactly in places where we want to handle errors and know how to handle them. The handler should analyze errors (custom error classes help) and rethrow unknown ones (maybe they are programming mistakes).
+- It's ok not to use `.catch` at all, if there's no way to recover from an error.
+- In any case we should have the `unhandledrejection` event handler (for browsers, and analogs for other environments) to track unhandled errors and inform the user (and probably our server) about them, so that our app never "just dies".
diff --git a/1-js/11-async/04-promise-error-handling/head.html b/1-js/11-async/04-promise-error-handling/head.html
index 31c6b42713..a0b7419623 100644
--- a/1-js/11-async/04-promise-error-handling/head.html
+++ b/1-js/11-async/04-promise-error-handling/head.html
@@ -1,16 +1,4 @@
-
-
-