diff --git a/1-js/7-advanced-syntax/index.md b/1-js/7-advanced-syntax/index.md index 2ddf0d29..fcebcff5 100644 --- a/1-js/7-advanced-syntax/index.md +++ b/1-js/7-advanced-syntax/index.md @@ -1 +1 @@ -# More syntax +# More syntax [todo move error handling] diff --git a/1-js/8-more-functions/04-global-object/article.md b/1-js/8-more-functions/04-global-object/article.md new file mode 100644 index 00000000..b1f4dada --- /dev/null +++ b/1-js/8-more-functions/04-global-object/article.md @@ -0,0 +1,171 @@ + + +# Global object + +When Javascript was created, there was an idea of a "global object" that provides all global variables and functions. It was planned that multiple in-browser scripts would use that single global object and share variables through it. + +Since then, Javascript greatly evolved, and that idea of linking code through global variables became much less appealing. In modern Javascript, the concept of modules too its place. + +But the global object still remains in the specification. + +In a browser it is named "window", for Node.JS it is "global", for other environments it may have another name. + +It does two things: + +1. Provides access to built-in functions and values, defined by the specification and the environment. + For instance, we can call `alert` directly or as a method of `window`: + + ```js run + alert("Hello"); + + // the same as + window.alert("Hello"); + ``` + + The same applies to other built-ins. E.g. we can use `window.Array` instead of `Array`. + +2. Provides access to global Function Declarations and `var` variables. We can read them and write using its properties, for instance: + + + ```js untrusted run no-strict refresh + var phrase = "Hello"; + + function sayHi() { + alert(phrase); + } + + // can read from window + alert( window.phrase ); // Hello (global var) + alert( window.sayHi ); // function (global function declaration) + + // can write to window (creates a new sglobal variable) + window.test = 5; + + alert(test); // 5 + ``` + +...But the global object does not have variables declared with `let/const`! + +```js untrusted run no-strict refresh +*!*let*/!* user = "John"; +alert(user); // John + +alert(window.user); // undefined, don't have let +alert("user" in window); // false +``` + +```smart header="The global object is not a global Environment Record" +In versions of ECMAScript prior to ES-2015, there were no `let/const` variables, only `var`. And global object was used as a global Environment Record (wordings were a bit different, but that's the gist). + +But starting from ES-2015, these entities are split apart. There's a global Lexical Environment with its Environment Record. And there's a global object that provides *some* of global variables. + +As a practical difference, global `let/const` variables are definitively properties of the global Environment Record, but they do not exist in the global object. + +Naturally, that's because the idea of a global object as a way to access "all global things" comes from ancient times. Nowadays is not considered to be a good thing. Modern language features like `let/const` do not make friends with it, but old ones are still compatible. +``` + +## Uses of "window" + +In server-side environments like Node.JS, the `global` object is used exceptionally rarely. Probably it would be fair to say "never". + +In-browser `window` is sometimes used though. + +Usually, it's not a good idea to use it, but here are some examples you can meet. + +1. To access exactly the global variable if the function has the local one with the same name. + + ```js untrusted run no-strict refresh + var user = "Global"; + + function sayHi() { + var user = "Local"; + + *!* + alert(window.user); // Global + */!* + } + + sayHi(); + ``` + + Such use is a workaround. Would be better to name variables differently, that won't require use to write the code it this way. And please note `"var"` before `user`. The trick doesn't work with `let` variables. + +2. To check if a certain global variable or a builtin exists. + + For instance, we want to check whether a global function `XMLHttpRequest` exists. + + We can't write `if (XMLHttpRequest)`, because if there's no `XMLHttpRequest`, there will be an error (variable not defined). + + But we can read it from `window.XMLHttpRequest`: + + ```js run + if (window.XMLHttpRequest) { + alert('XMLHttpRequest exists!') + } + ``` + + If there is no such global function then `window.XMLHttpRequest` is just a non-existing object property. That's `undefined`, no error, so it works. + + We can also write the test without `window`: + + ```js + if (typeof XMLHttpRequest == 'function') { + /* is there a function XMLHttpRequest? */ + } + ``` + + This doesn't use `window`, but is (theoretically) less reliable, because `typeof` may use a local XMLHttpRequest, and we want the global one. + + +3. To take the variable from the right window. That's probably the most valid use case. + + A browser may open multiple windows and tabs. A window may also embed another one in ` + + + ``` + + Here, first two alerts use the current window, and the latter two take variables from `iframe` window. Can be any variables if `iframe` originates from the same protocol/host/port. + +## "this" and global object + +Sometimes, the value of `this` is exactly the global object. That's rarely used, but some scripts rely on that. + +1. In the browser, the value of `this` in the global area is `window`: + + ```js run + // outside of functions + alert( this === window ); // true + ``` + + Other, non-browser environments, may use another value for `this` in such cases. + +2. When a function with `this` is called in not-strict mode, it gets the global object as `this`: + ```js run no-strict + // not in strict mode (!) + function f() { + alert(this); // [object Window] + } + + f(); // called without an object + ``` + + By specification, `this` in this case must be the global object, even in non-browser environments like Node.JS. That's for compatibility with old scripts, in strict mode `this` would be `undefined`. diff --git a/1-js/8-more-functions/04-function-object/2-counter-inc-dec/_js.view/solution.js b/1-js/8-more-functions/05-function-object/2-counter-inc-dec/_js.view/solution.js similarity index 100% rename from 1-js/8-more-functions/04-function-object/2-counter-inc-dec/_js.view/solution.js rename to 1-js/8-more-functions/05-function-object/2-counter-inc-dec/_js.view/solution.js diff --git a/1-js/8-more-functions/04-function-object/2-counter-inc-dec/_js.view/source.js b/1-js/8-more-functions/05-function-object/2-counter-inc-dec/_js.view/source.js similarity index 100% rename from 1-js/8-more-functions/04-function-object/2-counter-inc-dec/_js.view/source.js rename to 1-js/8-more-functions/05-function-object/2-counter-inc-dec/_js.view/source.js diff --git a/1-js/8-more-functions/04-function-object/2-counter-inc-dec/_js.view/test.js b/1-js/8-more-functions/05-function-object/2-counter-inc-dec/_js.view/test.js similarity index 100% rename from 1-js/8-more-functions/04-function-object/2-counter-inc-dec/_js.view/test.js rename to 1-js/8-more-functions/05-function-object/2-counter-inc-dec/_js.view/test.js diff --git a/1-js/8-more-functions/04-function-object/2-counter-inc-dec/solution.md b/1-js/8-more-functions/05-function-object/2-counter-inc-dec/solution.md similarity index 100% rename from 1-js/8-more-functions/04-function-object/2-counter-inc-dec/solution.md rename to 1-js/8-more-functions/05-function-object/2-counter-inc-dec/solution.md diff --git a/1-js/8-more-functions/04-function-object/2-counter-inc-dec/task.md b/1-js/8-more-functions/05-function-object/2-counter-inc-dec/task.md similarity index 100% rename from 1-js/8-more-functions/04-function-object/2-counter-inc-dec/task.md rename to 1-js/8-more-functions/05-function-object/2-counter-inc-dec/task.md diff --git a/1-js/8-more-functions/04-function-object/5-sum-many-brackets/solution.md b/1-js/8-more-functions/05-function-object/5-sum-many-brackets/solution.md similarity index 94% rename from 1-js/8-more-functions/04-function-object/5-sum-many-brackets/solution.md rename to 1-js/8-more-functions/05-function-object/5-sum-many-brackets/solution.md index 53c2e28d..5c932691 100644 --- a/1-js/8-more-functions/04-function-object/5-sum-many-brackets/solution.md +++ b/1-js/8-more-functions/05-function-object/5-sum-many-brackets/solution.md @@ -1,14 +1,14 @@ 1. For the whole thing to work *anyhow*, the result of `sum` must be function. 2. That function must keep in memory the current value between calls. -3. According to the task, the function must become the number when used in `==`. Functions are objects, so the conversion happens as described in the chapter , and we can provide our own method that returns the number. +3. According to the task, the function must become the number when used in `==`. Functions are objects, so the conversion happens as described in the chapter , and we can provide our own method that returns the number. Now the code: ```js run function sum(a) { - var currentSum = a; + let currentSum = a; function f(b) { currentSum += b; @@ -53,4 +53,3 @@ function f(b) { ``` This `f` will be used in the next call, again return itself, so many times as needed. Then, when used as a number or a string -- the `toString` returns the `currentSum`. We could also use `Symbol.toPrimitive` or `valueOf` here for the conversion. - diff --git a/1-js/8-more-functions/04-function-object/5-sum-many-brackets/task.md b/1-js/8-more-functions/05-function-object/5-sum-many-brackets/task.md similarity index 100% rename from 1-js/8-more-functions/04-function-object/5-sum-many-brackets/task.md rename to 1-js/8-more-functions/05-function-object/5-sum-many-brackets/task.md diff --git a/1-js/8-more-functions/04-function-object/article.md b/1-js/8-more-functions/05-function-object/article.md similarity index 76% rename from 1-js/8-more-functions/04-function-object/article.md rename to 1-js/8-more-functions/05-function-object/article.md index bacc79d6..1c754ff3 100644 --- a/1-js/8-more-functions/04-function-object/article.md +++ b/1-js/8-more-functions/05-function-object/article.md @@ -5,16 +5,16 @@ As we already know, functions in Javascript are values. Every value in Javascript has the type. What type of value is a function? -In Javascript, a function is an object. +In Javascript, a function is an object. -From one side, they are callable "actions". From the other side, we can treat them as objects: add/remove properties, pass by reference etc. +A good way to imagine functions is as callable "action objects". We can not only call them, but also treat them as objects: add/remove properties, pass by reference etc. ## The "name" property -A function name is accessible as the "name" property. +Function objects contain few sometimes-useable properties. -For Function Declarations, it's obvious: +For instance, a function name is accessible as the "name" property: ```js run function sayHi() { @@ -24,7 +24,7 @@ function sayHi() { alert(sayHi.name); // sayHi ``` -But what's more funny, the name-assigning logic is smart. It also sticks the right name to function that are used in assignments: +What's more funny, the name-assigning logic is smart. It also sticks the right name to function that are used in assignments: ```js run let sayHi = function() { @@ -34,28 +34,28 @@ let sayHi = function() { alert(sayHi.name); // sayHi (works!) ``` -Also here, as a default parameter: +Also works if the assignment is done via a default value: ```js run function f(sayHi = function() {}) { alert(sayHi.name); // sayHi (works!) } -f(); +f(); ``` -In the specification, this is called a "contextual name". The function itself does not provide one, but in an assignment it's easy to figure out from context. +In the specification, this feature is called a "contextual name". If the function does not provide one, then in an assignment is figured out from the context. Object methods have names too: ```js run let user = { - - sayHi() { + + sayHi() { // ... }, - sayBye: function() { + sayBye: function() { // ... } @@ -65,7 +65,9 @@ alert(user.sayHi.name); // sayHi alert(user.sayBye.name); // sayBye ``` -There's no magic though. In other cases, when there's no way to figure out the right name, it's empty, like here: +There's no magic though. There are cases when there's no way to figure out the right name. + +Then it's empty, like here: ```js // function created inside array @@ -75,7 +77,7 @@ alert( arr[0].name ); // // the engine has no way to set up the right name, so there is none ``` -In practice, most functions do have a name. It's mostly used for debugging and checking. +In practice, most functions do have a name. ## The "length" property @@ -93,11 +95,18 @@ alert(many.length); // 2 Here we can see that rest parameters are not counted. -The `length` property is sometimes used for introspection: what kind of function we have? +The `length` property is sometimes used for introspection in functions that operate on other functions. -For instance, in the code below `ask` function accepts `question` to ask and an arbitrary number of `handler` functions to call. +For instance, in the code below `ask` function accepts a `question` to ask and an arbitrary number of `handler` functions to call. -Each handler may be either a zero-argument function, then it is only called for a positive answer, or a single(or more)-argument function, then it is called with any answer as an argument. +When a user answers, it calls the handlers. We can pass two kinds of handlers: + +- A zero-argument function, then it is only called for a positive answer. +- A function with arguments, then it is called in any case and gets the answer. + +The idea is that we have a simple no-arguments handler syntax for positive cases (most often variant), but allow to provide universal handlers as well. + +To call `handlers` the right way, we examine the `length` property: ```js run function ask(question, ...handlers) { @@ -108,9 +117,9 @@ function ask(question, ...handlers) { if (isYes) handler(); } else { handler(isYes); - } + } } - + } // for positive answer, both handlers are called @@ -118,7 +127,7 @@ function ask(question, ...handlers) { ask("Question?", () => alert('You said yes'), result => alert(result)); ``` -This is a particular case of [polymorphism](https://en.wikipedia.org/wiki/Polymorphism_(computer_science)) -- treating arguments differently depending on their type -- or, in our case of their `length`. +This is a particular case of so-called [polymorphism](https://en.wikipedia.org/wiki/Polymorphism_(computer_science)) -- treating arguments differently depending on their type or, in our case depending on the `length`. The idea does have a use in Javascript libraries. ## Custom properties @@ -137,8 +146,8 @@ function sayHi() { } sayHi.counter = 0; // initial value -sayHi(); // Hi -sayHi(); // Hi +sayHi(); // Hi +sayHi(); // Hi alert( `Called ${sayHi.counter} times` ); // Called 2 times ``` @@ -149,7 +158,7 @@ A property assigned to a function like `sayHi.counter = 0` does *not* define a l We can treat a function as an object, store properties in it, but that has no effect on its execution. Variables never use function properties and vise versa. These are just parallel words. ``` -Also we can rewrite the counter example from the chapter to use function property instead of the closure: +Function properties can replace the closure sometimes. For instance, we can rewrite the counter example from the chapter to use a function property: ```js run function makeCounter() { @@ -157,7 +166,7 @@ function makeCounter() { // let count = 0 function counter() { - return counter.count++; + return counter.count++; }; counter.count = 0; @@ -170,7 +179,7 @@ alert( counter() ); // 0 alert( counter() ); // 1 ``` -Unlike examples from chapter , the `count` is now stored in the function directly, not in its outer Lexical Environment. +The `count` is now stored in the function directly, not in its outer Lexical Environment. Is it worse or better than using the closure? @@ -200,7 +209,7 @@ So it depends on our aims which variant to choose. ## Named Function Expression -Named Function Expression or, shortly, NFE, is a term a Function Expression that has a name. +Named Function Expression or, shortly, NFE, is a term for Function Expressions that have a name. For instance, let's take an ordinary Function Expression: @@ -218,7 +227,7 @@ let sayHi = function *!*func*/!*(who) { }; ``` -What's the role of that additional `"func"` name? +Did we do anything sane here? What's the role of that additional `"func"` name? First let's note, that we still have a Function Expression. Adding the name `"func"` after `function` did not make it a Function Declaration, because it is still created as a part of an assignment expression. @@ -226,7 +235,7 @@ Adding such a name also did not break anything. The function is still available as `sayHi()`: -```js run +```js run let sayHi = function *!*func*/!*(who) { alert(`Hello, ${who}`); }; @@ -322,7 +331,7 @@ Now it works, because the name `"func"` is function-local. It is not taken from The outer code still has it's variable `sayHi` or `welcome` later. And `func` is an "internal function name", how it calls itself privately. ```smart header="No such thing for Function Declaration" -The "internal name" feature described here is only available for Function Expressions, not to Function Declarations. For Function Declarations, there's just no syntax possibility to add a one more "internal" name for them. +The "internal name" feature described here is only available for Function Expressions, not to Function Declarations. For Function Declarations, there's just no syntax possibility to add a one more "internal" name for them. Sometimes, when we need a reliable internal name, it's the reason to rewrite a Function Declaration to Named Function Expression form. ``` @@ -343,4 +352,3 @@ Also, functions may carry additional properties. Many well-known Javascript libr They create a "main" function and attach many other "helper" functions to it. For instance, the [jquery](https://jquery.com) library creates a function named `$`. The [lodash](https://lodash.com) library creates a function `_`. And then adds `_.clone`, `_.keyBy` and other properties to (see the [docs](https://lodash.com/docs) when you want learn more about them). Actually, they do it to less pollute the global space, so that a single library gives only one global variable. That lowers the chance of possible naming conflicts. So, a function can do a useful job by itself and also carry a bunch of other functionality in properties. - diff --git a/1-js/8-more-functions/05-new-function/article.md b/1-js/8-more-functions/06-new-function/article.md similarity index 96% rename from 1-js/8-more-functions/05-new-function/article.md rename to 1-js/8-more-functions/06-new-function/article.md index e1ff92ef..2891bd91 100644 --- a/1-js/8-more-functions/05-new-function/article.md +++ b/1-js/8-more-functions/06-new-function/article.md @@ -48,9 +48,9 @@ It is used in very specific cases, like when we receive the code from the server ## The closure -Usually, a function remembers where it was born in the special property `[[Environment]] which references the current Lexical Environment. +Usually, a function remembers where it was born in the special property `[[Environment]]`. It references the Lexical Environment from where it's created. -But when a function is created using `new Function`, its `[[Environment]]` references not the current Lexical Environment, got the global one. +But when a function is created using `new Function`, its `[[Environment]]` references not the current Lexical Environment, but instead the global one. ```js run diff --git a/1-js/8-more-functions/07-call-apply-decorators/decorator-makecaching-wrapper.png b/1-js/8-more-functions/07-call-apply-decorators/decorator-makecaching-wrapper.png deleted file mode 100644 index 430a4cec..00000000 Binary files a/1-js/8-more-functions/07-call-apply-decorators/decorator-makecaching-wrapper.png and /dev/null differ diff --git a/1-js/8-more-functions/07-call-apply-decorators/decorator-makecaching-wrapper@2x.png b/1-js/8-more-functions/07-call-apply-decorators/decorator-makecaching-wrapper@2x.png deleted file mode 100644 index 296e2806..00000000 Binary files a/1-js/8-more-functions/07-call-apply-decorators/decorator-makecaching-wrapper@2x.png and /dev/null differ diff --git a/1-js/8-more-functions/06-settimeout-setinterval/1-output-numbers-100ms/solution.md b/1-js/8-more-functions/07-settimeout-setinterval/1-output-numbers-100ms/solution.md similarity index 100% rename from 1-js/8-more-functions/06-settimeout-setinterval/1-output-numbers-100ms/solution.md rename to 1-js/8-more-functions/07-settimeout-setinterval/1-output-numbers-100ms/solution.md diff --git a/1-js/8-more-functions/06-settimeout-setinterval/1-output-numbers-100ms/task.md b/1-js/8-more-functions/07-settimeout-setinterval/1-output-numbers-100ms/task.md similarity index 100% rename from 1-js/8-more-functions/06-settimeout-setinterval/1-output-numbers-100ms/task.md rename to 1-js/8-more-functions/07-settimeout-setinterval/1-output-numbers-100ms/task.md diff --git a/1-js/8-more-functions/06-settimeout-setinterval/3-rewrite-settimeout-0/solution.md b/1-js/8-more-functions/07-settimeout-setinterval/3-rewrite-settimeout/solution.md similarity index 100% rename from 1-js/8-more-functions/06-settimeout-setinterval/3-rewrite-settimeout-0/solution.md rename to 1-js/8-more-functions/07-settimeout-setinterval/3-rewrite-settimeout/solution.md diff --git a/1-js/8-more-functions/06-settimeout-setinterval/3-rewrite-settimeout-0/task.md b/1-js/8-more-functions/07-settimeout-setinterval/3-rewrite-settimeout/task.md similarity index 70% rename from 1-js/8-more-functions/06-settimeout-setinterval/3-rewrite-settimeout-0/task.md rename to 1-js/8-more-functions/07-settimeout-setinterval/3-rewrite-settimeout/task.md index cc5c94a5..3c788170 100644 --- a/1-js/8-more-functions/06-settimeout-setinterval/3-rewrite-settimeout-0/task.md +++ b/1-js/8-more-functions/07-settimeout-setinterval/3-rewrite-settimeout/task.md @@ -4,7 +4,9 @@ importance: 4 # Rewrite setTimeout with setInterval -Rewrite the split counting function from setTimeout to setInterval: +Here's the function that uses nested `setTimeout` to split a job into pieces. + +Rewrite it to `setInterval`: ```js run let i = 0; @@ -19,6 +21,7 @@ function count() { setTimeout(count, 0); } + // a piece of heavy job for(let j = 0; j < 1000000; j++) { i++; } @@ -27,4 +30,3 @@ function count() { count(); ``` - diff --git a/1-js/8-more-functions/06-settimeout-setinterval/4-settimeout-result/solution.md b/1-js/8-more-functions/07-settimeout-setinterval/4-settimeout-result/solution.md similarity index 100% rename from 1-js/8-more-functions/06-settimeout-setinterval/4-settimeout-result/solution.md rename to 1-js/8-more-functions/07-settimeout-setinterval/4-settimeout-result/solution.md diff --git a/1-js/8-more-functions/06-settimeout-setinterval/4-settimeout-result/task.md b/1-js/8-more-functions/07-settimeout-setinterval/4-settimeout-result/task.md similarity index 100% rename from 1-js/8-more-functions/06-settimeout-setinterval/4-settimeout-result/task.md rename to 1-js/8-more-functions/07-settimeout-setinterval/4-settimeout-result/task.md diff --git a/1-js/8-more-functions/06-settimeout-setinterval/article.md b/1-js/8-more-functions/07-settimeout-setinterval/article.md similarity index 78% rename from 1-js/8-more-functions/06-settimeout-setinterval/article.md rename to 1-js/8-more-functions/07-settimeout-setinterval/article.md index 61f3199d..54bce6a5 100644 --- a/1-js/8-more-functions/06-settimeout-setinterval/article.md +++ b/1-js/8-more-functions/07-settimeout-setinterval/article.md @@ -1,11 +1,13 @@ -# Scheduling: setTimeout and setInterval [todo tasks] +# Scheduling: setTimeout and setInterval + +We may decide to execute a function not right now, but at a certain time later. That's called *scheduling*. There are two methods to schedule function execution: -- `setTimeout` allows the function to run once after the given interval of time. -- `setInterval` allows the function to run regularly. +- `setTimeout` allows to run a function once after the given interval of time. +- `setInterval` allows to run of the function regularly with the given interval between the runs. -These methods are not the part of Javascript specification. But most environments have internal scheduler and provide these methods. In particular, they are supported in all browsers and Node.JS. +These methods are not a part of Javascript specification. But most environments have the internal scheduler and provide these methods. In particular, they are supported in all browsers and Node.JS. [cut] @@ -55,7 +57,7 @@ setTimeout(sayHi, 1000, "John", "Hello"); // Hello, John */!* ``` -If the first argument is a string, then Javascript creates a function from it. +If the first argument is a string, then Javascript creates a function from it. So, this will also work: @@ -76,12 +78,12 @@ Novice developers sometimes make a mistake by adding brackets `()` after the fun // wrong! setTimeout(sayHi(), 1000); ``` -That doesn't work, because `setTimeout` expects a reference to function. And here `sayHi()` runs the function, and the result of its execution is passed as the first argument. In our case the result of `sayHi()` is `undefined` (function returns nothing), so nothing is scheduled. +That doesn't work, because `setTimeout` expects a reference to function. And here `sayHi()` runs the function, and the *result of its execution* is passed as the first argument. In our case the result of `sayHi()` is `undefined` (the function returns nothing), so nothing is scheduled. ```` ### Canceling with clearTimeout -The call to `setTimeout` returns a "timer identifier" `timerId`, that we can use to cancel the execution. +A call to `setTimeout` returns a "timer identifier" `timerId`, that we can use to cancel the execution. The syntax to cancel: @@ -94,7 +96,7 @@ In the code below we schedule the function, and then cancel it (changed our mind ```js run no-beautify let timerId = setTimeout(() => alert("never happens"), 1000); -alert(timerId); // timer identifier +alert(timerId); // timer identifier clearTimeout(timerId); alert(timerId); // same identifier (doesn't become null after canceling) @@ -131,7 +133,7 @@ setTimeout(() => { clearInterval(timerId); alert('stop'); }, 5000); ```smart header="Modal windows freeze time in Chrome/Opera/Safari" In browsers Chrome, Opera and Safari the internal timer is "frozen" while showing `alert/confirm/prompt`. And in IE or Firefox it continues ticking. -So if you run the code above and hold the `alert` window for a long time, then in Firefox/IE next `alert` will be shown at once (internal timer ticked up), and in Chrome/Opera/Safari -- after 2 seconds. +So if you run the code above and hold the `alert` window for a long time, then in Firefox/IE next `alert` will be shown at once (2 seconds passed from the previous run), and in Chrome/Opera/Safari -- after 2 seconds (timer does not tick during the `alert`). ``` ## Recursive setTimeout @@ -214,7 +216,7 @@ When a function is passed in `setInterval/setTimeout`, an internal reference is setTimeout(function() {}, 100); ``` -For `setInterval` the function stays in memory until `cancelInterval` is called. +For `setInterval` the function stays in memory until `cancelInterval` is called. A function references outer lexical environment, so, while it lives, certain outer variables live too. They may take much more memory than the function itself. That's a good reason to keep an eye on scheduled functions` and cancel them once they are not needed. ```` @@ -239,7 +241,7 @@ The trick is also used to split a CPU-hungry task. For instance, syntax highlighting script, used to colorize code examples on this page, is quite CPU-heavy. To hightlight the code, it analyzes it, creates many colored highlighting elements, adds them to the document -- for a big text that takes a lot. It may even cause the browser to "hang", that's unacceptable. -So we can split the long text to pieces. First 100 lines, then plan another 100 lines using `setTimeout(...,0)`, and so on. +So we can split the long text to pieces. First 100 lines, then plan another 100 lines using `setTimeout(...,0)`, and so on. As a simpler example -- here's a counting function from `1` to `1000000000`. @@ -252,6 +254,7 @@ let start = Date.now(); function count() { + // do a heavy job for(let j = 0; j < 1000000000; j++) { i++; } @@ -262,7 +265,7 @@ function count() { count(); ``` -Now the split version: +Let's split the job using the nested `setTimeout`: ```js run let i = 0; @@ -271,12 +274,13 @@ let start = Date.now(); function count() { - if (i == 1000000000) { + if (i == 100000000) { alert("Done in " + (Date.now() - start) + 'ms'); } else { - setTimeout(count, 0); + setTimeout(count, 0); // schedule the new call (*) } + // do a piece of the heavy job (**) for(let j = 0; j < 1000000; j++) { i++; } @@ -286,15 +290,13 @@ function count() { count(); ``` - Now the browser UI is fully functional. Pauses between `count` executions provide just enough "breath" for the browser to do something else, to react on other user actions. The notable thing is that both variants are comparable in speed. There's no much difference in the overall counting time. -Note that `setTimeout(count, 0)` is planned before the counting. That's actually a small workaround. The [HTML5 standard](https://www.w3.org/TR/html5/webappapis.html#timers) says: "after five nested timers..., the interval is forced to be at least four milliseconds.". That limitation exists mainly for historical reasons. +Note that in the example above the next call is planned before the counting itself: line `(*)` goes before the loop `(**)`. That plans making the new call as early as possible. - -For us it means that first 5 invocations will run one right after another, and then 4ms delay will be added between them. +If we switch them, the overall time will be much slower. Here's the code with `setTimeout` at the end to compare: @@ -309,9 +311,9 @@ function count() { i++; } - // moved to "after the job" + // moved re-scheduling to "after the job" *!* - if (i == 1000000000) { + if (i == 100000000) { alert("Done in " + (Date.now() - start) + 'ms'); } else { setTimeout(count, 0); @@ -323,14 +325,33 @@ function count() { count(); ``` -If you run it, easy to notice that it takes significantly more time. Just because of these additional delays. The good thing is that the browser now has even more time between the invocations to go elsewhere. +If you run it, easy to notice that it takes significantly more time. +````smart header="Minimal delay of nested timers in-browser" +In the browser, there's a limitation of how often nested timers can run. The [HTML5 standard](https://www.w3.org/TR/html5/webappapis.html#timers) says: "after five nested timers..., the interval is forced to be at least four milliseconds.". -```smart header="Server-side Javascript" -For server-side Javascript, the "four ms" limitation does not exist. Also, there are other ways to schedule an immediate asynchronous job. In Node.JS that's [process.nextTick](https://nodejs.org/api/process.html) and [setImmediate](https://nodejs.org/api/timers.html). +To see that, let's timers immediately and measure times between them: + +```js run +let start = Date.now(), times = []; + +setTimeout(function run() { + times.push(Date.now() - start); + + if (start + 100 > Date.now()) setTimeout(run, 0); + else alert(times); +}, 0); + +// an example of the output: +// 1,1,1,1,9,15,20,24,30,35,40,45,50,55,59,64,70,75,80,85,90,95,100 ``` -## Итого +First timers run immediately (just as written in the spec), and then the delay comes into play. That limitation comes from ancient times and many scripts rely on it, so it exists for historical reasons. + +For server-side Javascript, that limitation does not exist. Also, there are other ways to schedule an immediate asynchronous job. In Node.JS that's [process.nextTick](https://nodejs.org/api/process.html) and [setImmediate](https://nodejs.org/api/timers.html). +```` + +## Summary [todo] - Методы `setInterval(func, delay)` и `setTimeout(func, delay)` позволяют запускать `func` регулярно/один раз через `delay` миллисекунд. - Оба метода возвращают идентификатор таймера. Его используют для остановки выполнения вызовом `clearInterval/clearTimeout`. @@ -339,4 +360,3 @@ For server-side Javascript, the "four ms" limitation does not exist. Also, there - В реальности срабатывания таймера могут быть гораздо реже, чем назначено, например если процессор перегружен, вкладка находится в фоновом режиме, ноутбук работает от батареи или по какой-то иной причине. Браузерных особенностей почти нет, разве что вызов `setInterval(..., 0)` с нулевой задержкой в IE недопустим, нужно указывать `setInterval(..., 1)`. - diff --git a/1-js/8-more-functions/06-settimeout-setinterval/setinterval-interval.png b/1-js/8-more-functions/07-settimeout-setinterval/setinterval-interval.png similarity index 100% rename from 1-js/8-more-functions/06-settimeout-setinterval/setinterval-interval.png rename to 1-js/8-more-functions/07-settimeout-setinterval/setinterval-interval.png diff --git a/1-js/8-more-functions/06-settimeout-setinterval/setinterval-interval@2x.png b/1-js/8-more-functions/07-settimeout-setinterval/setinterval-interval@2x.png similarity index 100% rename from 1-js/8-more-functions/06-settimeout-setinterval/setinterval-interval@2x.png rename to 1-js/8-more-functions/07-settimeout-setinterval/setinterval-interval@2x.png diff --git a/1-js/8-more-functions/06-settimeout-setinterval/settimeout-interval.png b/1-js/8-more-functions/07-settimeout-setinterval/settimeout-interval.png similarity index 100% rename from 1-js/8-more-functions/06-settimeout-setinterval/settimeout-interval.png rename to 1-js/8-more-functions/07-settimeout-setinterval/settimeout-interval.png diff --git a/1-js/8-more-functions/06-settimeout-setinterval/settimeout-interval@2x.png b/1-js/8-more-functions/07-settimeout-setinterval/settimeout-interval@2x.png similarity index 100% rename from 1-js/8-more-functions/06-settimeout-setinterval/settimeout-interval@2x.png rename to 1-js/8-more-functions/07-settimeout-setinterval/settimeout-interval@2x.png diff --git a/1-js/8-more-functions/07-call-apply-decorators/2-spy-decorator/_js.view/solution.js b/1-js/8-more-functions/08-call-apply-decorators/2-spy-decorator/_js.view/solution.js similarity index 100% rename from 1-js/8-more-functions/07-call-apply-decorators/2-spy-decorator/_js.view/solution.js rename to 1-js/8-more-functions/08-call-apply-decorators/2-spy-decorator/_js.view/solution.js diff --git a/1-js/8-more-functions/07-call-apply-decorators/2-spy-decorator/_js.view/source.js b/1-js/8-more-functions/08-call-apply-decorators/2-spy-decorator/_js.view/source.js similarity index 100% rename from 1-js/8-more-functions/07-call-apply-decorators/2-spy-decorator/_js.view/source.js rename to 1-js/8-more-functions/08-call-apply-decorators/2-spy-decorator/_js.view/source.js diff --git a/1-js/8-more-functions/07-call-apply-decorators/2-spy-decorator/_js.view/test.js b/1-js/8-more-functions/08-call-apply-decorators/2-spy-decorator/_js.view/test.js similarity index 100% rename from 1-js/8-more-functions/07-call-apply-decorators/2-spy-decorator/_js.view/test.js rename to 1-js/8-more-functions/08-call-apply-decorators/2-spy-decorator/_js.view/test.js diff --git a/1-js/8-more-functions/07-call-apply-decorators/2-spy-decorator/solution.md b/1-js/8-more-functions/08-call-apply-decorators/2-spy-decorator/solution.md similarity index 100% rename from 1-js/8-more-functions/07-call-apply-decorators/2-spy-decorator/solution.md rename to 1-js/8-more-functions/08-call-apply-decorators/2-spy-decorator/solution.md diff --git a/1-js/8-more-functions/07-call-apply-decorators/2-spy-decorator/task.md b/1-js/8-more-functions/08-call-apply-decorators/2-spy-decorator/task.md similarity index 100% rename from 1-js/8-more-functions/07-call-apply-decorators/2-spy-decorator/task.md rename to 1-js/8-more-functions/08-call-apply-decorators/2-spy-decorator/task.md diff --git a/1-js/8-more-functions/07-call-apply-decorators/8-debounce/_js.view/solution.js b/1-js/8-more-functions/08-call-apply-decorators/8-debounce/_js.view/solution.js similarity index 100% rename from 1-js/8-more-functions/07-call-apply-decorators/8-debounce/_js.view/solution.js rename to 1-js/8-more-functions/08-call-apply-decorators/8-debounce/_js.view/solution.js diff --git a/1-js/8-more-functions/07-call-apply-decorators/8-debounce/_js.view/test.js b/1-js/8-more-functions/08-call-apply-decorators/8-debounce/_js.view/test.js similarity index 100% rename from 1-js/8-more-functions/07-call-apply-decorators/8-debounce/_js.view/test.js rename to 1-js/8-more-functions/08-call-apply-decorators/8-debounce/_js.view/test.js diff --git a/1-js/8-more-functions/07-call-apply-decorators/8-debounce/solution.md b/1-js/8-more-functions/08-call-apply-decorators/8-debounce/solution.md similarity index 100% rename from 1-js/8-more-functions/07-call-apply-decorators/8-debounce/solution.md rename to 1-js/8-more-functions/08-call-apply-decorators/8-debounce/solution.md diff --git a/1-js/8-more-functions/07-call-apply-decorators/8-debounce/task.md b/1-js/8-more-functions/08-call-apply-decorators/8-debounce/task.md similarity index 100% rename from 1-js/8-more-functions/07-call-apply-decorators/8-debounce/task.md rename to 1-js/8-more-functions/08-call-apply-decorators/8-debounce/task.md diff --git a/1-js/8-more-functions/07-call-apply-decorators/9-throttle/_js.view/solution.js b/1-js/8-more-functions/08-call-apply-decorators/9-throttle/_js.view/solution.js similarity index 100% rename from 1-js/8-more-functions/07-call-apply-decorators/9-throttle/_js.view/solution.js rename to 1-js/8-more-functions/08-call-apply-decorators/9-throttle/_js.view/solution.js diff --git a/1-js/8-more-functions/07-call-apply-decorators/9-throttle/_js.view/test.js b/1-js/8-more-functions/08-call-apply-decorators/9-throttle/_js.view/test.js similarity index 100% rename from 1-js/8-more-functions/07-call-apply-decorators/9-throttle/_js.view/test.js rename to 1-js/8-more-functions/08-call-apply-decorators/9-throttle/_js.view/test.js diff --git a/1-js/8-more-functions/07-call-apply-decorators/9-throttle/solution.md b/1-js/8-more-functions/08-call-apply-decorators/9-throttle/solution.md similarity index 100% rename from 1-js/8-more-functions/07-call-apply-decorators/9-throttle/solution.md rename to 1-js/8-more-functions/08-call-apply-decorators/9-throttle/solution.md diff --git a/1-js/8-more-functions/07-call-apply-decorators/9-throttle/task.md b/1-js/8-more-functions/08-call-apply-decorators/9-throttle/task.md similarity index 100% rename from 1-js/8-more-functions/07-call-apply-decorators/9-throttle/task.md rename to 1-js/8-more-functions/08-call-apply-decorators/9-throttle/task.md diff --git a/1-js/8-more-functions/07-call-apply-decorators/article.md b/1-js/8-more-functions/08-call-apply-decorators/article.md similarity index 53% rename from 1-js/8-more-functions/07-call-apply-decorators/article.md rename to 1-js/8-more-functions/08-call-apply-decorators/article.md index 46e8a077..e5773f16 100644 --- a/1-js/8-more-functions/07-call-apply-decorators/article.md +++ b/1-js/8-more-functions/08-call-apply-decorators/article.md @@ -1,36 +1,35 @@ # Decorators and forwarding, call/apply -Javascript has exceptionally flexible functions. They can be passed around, used as objects, and now we will see how one function can pass its call to another one transparently. We'll use it to wrap new functionality around existing functions. +Javascript gives exceptional flexibility when dealing with functions. They can be passed around, used as objects, and now we'll see how to *forward* calls between them and *decorate* them. [cut] ## Transparent caching -Let's say we have a function `slow(x)` which is CPU-heavy, but for same `x` it always returns the same value. +Let's say we have a function `slow(x)` which is CPU-heavy, but its results are stable. In other words, for same `x` it always returns the same result. -Naturally, we'd want to cache (remember) the result, so that on the same future call we can return it without executing the function. +If the function is called often, we may want to create a wrapper that caches (remembers) results for different `x`, to evade spending extra-time on recalculations. -But caching is something orthogonal to the function itself. So instead of mixing it into the function itself, we'll write a *caching decorator*. - -A working example is better than thousand words here: +Here's the code, and explanations follow: ```js run function slow(x) { - // Math.random() is used to make caching exceptionally noticeable - return x * Math.random(); // actually, there is a scary CPU-heavy task here + // there can be a heavy CPU-intensive job here + alert(`Called with ${x}`); + return x; } function cachingDecorator(func) { let cache = new Map(); return function(x) { - if (cache.has(x)) { // if in the map - return cache.get(x); // return + if (cache.has(x)) { // if the result is in the map + return cache.get(x); // return it } let result = func(x); // otherwise call func - - cache.set(x, result); // and remember + + cache.set(x, result); // and cache (remember) the result return result; }; } @@ -38,19 +37,25 @@ function cachingDecorator(func) { slow = cachingDecorator(slow); alert( slow(1) ); // slow(1) is cached -alert( slow(1) ); // the same +alert( "Again: " + slow(1) ); // the same alert( slow(2) ); // slow(2) is cached -alert( slow(2) ); // the same as the previous line +alert( "Again: " + slow(2) ); // the same as the previous line ``` In the code above `cachingDecorator` is a *decorator*: a special function that takes another function and alters its behavior. +The idea is that we can call `cachingDecorator` for any function and get its "caching" variant. That's great, because we can have many functions that could use such a feature, and all we need to do is to apply `cachingDecorator` to them. + +No need to modify the code of `slow` to add a feature -- we separate concerns and keep it simple. + +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: ![](decorator-makecaching-wrapper.png) -As we can see, the decorator did not change how function works. From an outside, the wrapped `slow` function still does the same. It just got a caching aspect added to its behavior. +As we can see, the wrapper does not change the result here. From an outside code, the wrapped `slow` function still does the same. It just got a caching aspect added to its behavior. There are several benefits of using a separate `cachingDecorator` instead of altering the code of `slow` itself: @@ -67,52 +72,56 @@ The caching decorator mentioned above is not suited to work with object methods. For instance, in the code below `user.format()` stops working after the decoration: ```js run -let obj = { - random() { - return Math.random(); // actually, there is a scary CPU-heavy task here +// we'll make worker.slow caching +let worker = { + someMethod() { + return 1; }, slow(x) { -*!* - return this.random() * x; // (*) -*/!* + // actually, there can be a scary CPU-heavy task here + alert("Called with " + x); + return x * this.someMethod(); // (*) } }; +// same code as before function cachingDecorator(func) { let cache = new Map(); return function(x) { if (cache.has(x)) { - return cache.get(x); + return cache.get(x); } *!* - let result = func(x); // "this" is not passed (**) + let result = func(x); // (**) */!* - cache.set(x, result); + cache.set(x, result); return result; }; } -alert( obj.slow(1) ); // the original method works +alert( worker.slow(1) ); // the original method works -obj.slow = cachingDecorator(obj.slow); // now make it caching +worker.slow = cachingDecorator(worker.slow); // now make it caching *!* -alert( obj.slow(2) ); // WOPS! Error: Cannot read property 'random' of undefined +alert( worker.slow(2) ); // WOPS! Error: Cannot read property 'someMethod' of undefined */!* ``` -The error actually happens in the line `(*)` that tries to access `this.random` and fails. Guess you can see, why? +The error occurs in the line `(*)` that tries to access `this.someMethod` and fails. Guess you can see, why? -The decorated `obj.slow` calls the original one as `func(x)` in the line `(**)`. In this manner, the function always gets `this = undefined`. +The reason is that the wrapper calls the original function as `func(x)` in the line `(**)`. And, when called like this, the function gets `this = undefined`. As if we run: ```js -let func = obj.slow; +let func = worker.slow; func(2); ``` +So, the wrapper passes the call to the original method, but without the context `this`. Hence the error. + Let's fix it. There's a special built-in function method [func.call(context, ...args)](mdn:js/Function/call) that allows to call a function explicitly setting `this`. @@ -125,7 +134,15 @@ func.call(context, arg1, arg2, ...) It runs the `func` providing the first argument as `this`, and the next as the arguments. -For instance, in the code below `sayHi.call(user)` runs `sayHi`, providing `this=user`. And the next line sets `this=admin`: +To put it simple, these two calls do almost the same: +```js +func(1, 2, 3); +func.call(obj, 1, 2, 3) +``` + +They both call `func` with arguments `1`, `2` and `3`. The only difference is that `func.call` also sets `this` to `obj`. + +As an example, in the code below we call `sayHi` in the context of different objects: `sayHi.call(user)` runs `sayHi` providing `this=user`, and the next line sets `this=admin`: ```js run function sayHi() { @@ -136,8 +153,8 @@ let user = { name: "John" }; let admin = { name: "Admin" }; // use call to pass different objects as "this" -sayHi.call( user ); // John -sayHi.call( admin ); // Admin +sayHi.call( user ); // John +sayHi.call( admin ); // Admin ``` And here we use `call` to call `say` with the given context and phrase: @@ -150,28 +167,23 @@ function say(phrase) { let user = { name: "John" }; +// user becomes this, and "Hello" becomes the first argument say.call( user, "Hello" ); // John: Hello ``` -To put it simple, these calls are almost equivalent: -```js -func(1, 2, 3); -func.call(obj, 1, 2, 3) -``` -They both call `func` with arguments `1`, `2` and `3`. The only difference is that `call` also sets `this` to `obj`. - -For our case, the wrapper should pass the context that it gets to the original function: +For our case, we can use `call` in the wrapper to pass the context to the original function: ```js run -let obj = { - random() { - return Math.random(); // actually, there is a scary CPU-heavy task here +let worker = { + someMethod() { + return 1; }, slow(x) { - return this.random() * x; + alert("Called with " + x); + return x * this.someMethod(); // (*) } }; @@ -179,29 +191,29 @@ function cachingDecorator(func) { let cache = new Map(); return function(x) { if (cache.has(x)) { - return cache.get(x); + return cache.get(x); } *!* - let result = func.call(this, x); // "this" is passed + let result = func.call(this, x); // "this" is passed correctly now */!* - cache.set(x, result); + cache.set(x, result); return result; }; } -obj.slow = cachingDecorator(obj.slow); // now make it caching +worker.slow = cachingDecorator(worker.slow); // now make it caching -alert( obj.slow(2) ); // works -alert( obj.slow(2) ); // same (cached) +alert( worker.slow(2) ); // works +alert( worker.slow(2) ); // works, doesn't call the original (cached) ``` Now everything is fine. -To prevent misunderstandings, let's see more deeply into what's going on during `obj.slow(2)` call: +To put all clear, let's see more deeply how `this` is passed along: -1. After the decoration `obj.slow` is now the wrapper `function (x) { ... }`. -2. So when `obj.slow(2)` is executed, the wrapper gets `this` set to `obj` (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` (`=obj`) and the current argument further to the original method. +1. After the decoration `worker.slow` is now the wrapper `function (x) { ... }`. +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" @@ -209,34 +221,34 @@ Now let's make `cachingDecorator` even more universal. Till now it was working o Now how to cache this `obj.slow`? -```js -let obj = { +```js +let worker = { slow(min, max) { - // returns a random number from min to max - return min + Math.random() * (max - min); // scary CPU-hogger is assumed + return min + max; // scary CPU-hogger is assumed } }; // should remember same-argument calls -obj.slow = cachingDecorator(obj.slow); +worker.slow = cachingDecorator(worker.slow); ``` -We have two tasks to solve here. +We have two tasks to solve here. -First is how to use both arguments `min` and `max` for the key in `cache` map. Previously, 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*. The native `Map` takes single value only as the key. +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*. The native `Map` takes single value only as the key. There are many solutions possible: -1. Implement (or use a third-party) a new map-like data structure that is more versatile and allows such keys. -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)`. +1. Implement (or use a third-party) a new map-like data structure that is more versatile and allows multi-keys. +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. Allow to provide a *hashing function* for the decorator, that knows how to make a one value from many. -For our particular case and for many practical applications, the 3rd variant is good enough. +For our case and many practical applications, the 3rd variant is good enough. -The second is how to pass many arguments to `func`. Currently, the wrapper `function(x)` assumes a single argument, and `func.call(this, x)` passes 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). +Here we can use another built-in method [func.apply](mdn:js/Function/apply). The syntax is: @@ -246,14 +258,6 @@ func.apply(context, args) It runs the `func` setting `this=context` and using an array-like object `args` as the list of arguments. -```smart header="Reminder: array-likes and iterables" -Array-like objects are those that have `length` and indexed properties. Iterables are those that have `Symbol.iterator` method. - -Arrays are both array-like and iterable. More on that in the chapter . -``` - - - For instance, these two calls are almost the same: @@ -276,33 +280,36 @@ 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) */!* ``` -Actually, 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. +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. -These two calls do the same: +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); -func.apply(context, args); +func.call(context, ...args); // pass an array as list with spread operator +func.apply(context, args); // is same as using apply */!* ``` -If we come closer, there's a minor difference between such uses of `call` and `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, where we expect an iterable, `call` works, where we expect an array-like, `apply` works. +So, these calls complement to each other. Where we expect an iterable, `call` works, where we expect an array-like, `apply` works. -If something is both iterable and array-like, like a real array, then we should use `apply`, because it is is more optimized internally than `call + spread`. +If something 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, more optimized inside the engines internally than a pair `call + spread`. -The universal "wrapper formula" that allows to pass everything to another function is: +We can use `apply` to pass everything to another function like this: ```js let wrapper = function() { @@ -310,16 +317,17 @@ let wrapper = function() { }; ``` -That's called *call forwarding*. The `wrapper` passes everything it gets: context and arguments to `anotherFunction` and returns back its result. +That's called *call forwarding*. The `wrapper` passes everything it gets: the context `this` and arguments to `anotherFunction` and returns back its result. When an external code calls such `wrapper`, it is undistinguishable from the call of the original function. -Finally, the all-powerful `cachingDecorator`: +Finally, let's bake it all into the more powerful `cachingDecorator`: ```js run -let obj = { +let worker = { slow(min, max) { - return min + Math.random() * (max - min); + alert(`Called with ${min},${max}`); + return min + max; } }; @@ -330,14 +338,14 @@ function cachingDecorator(func, hash) { let key = hash(arguments); // (*) */!* if (cache.has(key)) { - return cache.get(key); + return cache.get(key); } *!* let result = func.apply(this, arguments); // (**) */!* - cache.set(key, result); + cache.set(key, result); return result; }; } @@ -346,15 +354,13 @@ function hash(args) { return args[0] + ',' + args[1]; } -obj.slow = cachingDecorator(obj.slow, hash); +worker.slow = cachingDecorator(worker.slow, hash); -alert( obj.slow(3, 5) ); // works -alert( obj.slow(3, 5) ); // same (cached) - -alert( obj.slow(2, 5) ); // another value +alert( worker.slow(3, 5) ); // works +alert( "Again " + worker.slow(3, 5) ); // same (cached) ``` -Now the wrapper operates with any number of arguments. +Now the wrapper operates with any number of arguments. There are two changes: @@ -382,9 +388,9 @@ function hash(args) { } ``` -...Unfortunately, that won't work. Because `hash(arguments)` receives `arguments` object, and it 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 fails: +So calling `join` on it would fail, as we can see below: ```js run function hash() { @@ -412,21 +418,21 @@ 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`. -The internal algorithm of native method `[].join` is very simple. It's like this: +Why does it work? + +That's because the internal algorithm of the native method `arr.join(glue)` is very simple. + +Taken from the specification almost "as-is": 1. Let `glue` be the first argument or, if no arguments, then a comma `","`. 2. Let `result` be an empty string. 3. Append `this[0]` to `result`. -4. Append `glue`. -5. Append `this[1]`. -6. Append `glue`. -7. Append `this[2]` -8. ...Until `this.length` items are glued. -9. Return `result`. +4. Append `glue` and `this[1]`. +5. Append `glue` and `this[2]`. +6. ...Do so until `this.length` items are glued. +7. Return `result`. -For arrays `arr.join()` has `this=arr`, so it joins the array `arr`. - -But it is written in a way that allows any array-like `this` (not a coincidence, many methods follow this practice), so it also works with `this=arguments`. +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`. ## Summary @@ -454,4 +460,3 @@ We also saw an example of *method borrowing* when we take a method from an objec There are many decorators there in the wilds. Check how well you got them by solving the tasks of this chapter. - diff --git a/1-js/8-more-functions/08-call-apply-decorators/decorator-makecaching-wrapper.png b/1-js/8-more-functions/08-call-apply-decorators/decorator-makecaching-wrapper.png new file mode 100644 index 00000000..171e2791 Binary files /dev/null and b/1-js/8-more-functions/08-call-apply-decorators/decorator-makecaching-wrapper.png differ diff --git a/1-js/8-more-functions/08-call-apply-decorators/decorator-makecaching-wrapper@2x.png b/1-js/8-more-functions/08-call-apply-decorators/decorator-makecaching-wrapper@2x.png new file mode 100644 index 00000000..8d3b5434 Binary files /dev/null and b/1-js/8-more-functions/08-call-apply-decorators/decorator-makecaching-wrapper@2x.png differ diff --git a/1-js/8-more-functions/08-bind/2-write-to-object-after-bind/solution.md b/1-js/8-more-functions/09-bind/2-write-to-object-after-bind/solution.md similarity index 100% rename from 1-js/8-more-functions/08-bind/2-write-to-object-after-bind/solution.md rename to 1-js/8-more-functions/09-bind/2-write-to-object-after-bind/solution.md diff --git a/1-js/8-more-functions/08-bind/2-write-to-object-after-bind/task.md b/1-js/8-more-functions/09-bind/2-write-to-object-after-bind/task.md similarity index 100% rename from 1-js/8-more-functions/08-bind/2-write-to-object-after-bind/task.md rename to 1-js/8-more-functions/09-bind/2-write-to-object-after-bind/task.md diff --git a/1-js/8-more-functions/08-bind/3-second-bind/solution.md b/1-js/8-more-functions/09-bind/3-second-bind/solution.md similarity index 100% rename from 1-js/8-more-functions/08-bind/3-second-bind/solution.md rename to 1-js/8-more-functions/09-bind/3-second-bind/solution.md diff --git a/1-js/8-more-functions/08-bind/3-second-bind/task.md b/1-js/8-more-functions/09-bind/3-second-bind/task.md similarity index 100% rename from 1-js/8-more-functions/08-bind/3-second-bind/task.md rename to 1-js/8-more-functions/09-bind/3-second-bind/task.md diff --git a/1-js/8-more-functions/08-bind/4-function-property-after-bind/solution.md b/1-js/8-more-functions/09-bind/4-function-property-after-bind/solution.md similarity index 100% rename from 1-js/8-more-functions/08-bind/4-function-property-after-bind/solution.md rename to 1-js/8-more-functions/09-bind/4-function-property-after-bind/solution.md diff --git a/1-js/8-more-functions/08-bind/4-function-property-after-bind/task.md b/1-js/8-more-functions/09-bind/4-function-property-after-bind/task.md similarity index 100% rename from 1-js/8-more-functions/08-bind/4-function-property-after-bind/task.md rename to 1-js/8-more-functions/09-bind/4-function-property-after-bind/task.md diff --git a/1-js/8-more-functions/08-bind/5-question-use-bind/solution.md b/1-js/8-more-functions/09-bind/5-question-use-bind/solution.md similarity index 100% rename from 1-js/8-more-functions/08-bind/5-question-use-bind/solution.md rename to 1-js/8-more-functions/09-bind/5-question-use-bind/solution.md diff --git a/1-js/8-more-functions/08-bind/5-question-use-bind/task.md b/1-js/8-more-functions/09-bind/5-question-use-bind/task.md similarity index 100% rename from 1-js/8-more-functions/08-bind/5-question-use-bind/task.md rename to 1-js/8-more-functions/09-bind/5-question-use-bind/task.md diff --git a/1-js/8-more-functions/08-bind/6-ask-currying/solution.md b/1-js/8-more-functions/09-bind/6-ask-currying/solution.md similarity index 100% rename from 1-js/8-more-functions/08-bind/6-ask-currying/solution.md rename to 1-js/8-more-functions/09-bind/6-ask-currying/solution.md diff --git a/1-js/8-more-functions/08-bind/6-ask-currying/task.md b/1-js/8-more-functions/09-bind/6-ask-currying/task.md similarity index 100% rename from 1-js/8-more-functions/08-bind/6-ask-currying/task.md rename to 1-js/8-more-functions/09-bind/6-ask-currying/task.md diff --git a/1-js/8-more-functions/08-bind/article.md b/1-js/8-more-functions/09-bind/article.md similarity index 52% rename from 1-js/8-more-functions/08-bind/article.md rename to 1-js/8-more-functions/09-bind/article.md index 32006fd6..1f8e3391 100644 --- a/1-js/8-more-functions/08-bind/article.md +++ b/1-js/8-more-functions/09-bind/article.md @@ -7,7 +7,7 @@ libs: When using `setTimeout` with object methods or passing object methods along, there's a known problem: "loosing `this`". -Suddenly, `this` just stops working right. The situation is typical for novice developers, but happens with experienced ones as well. +Suddenly, `this` just stops working right. The situation is typical for novice developers, but happens with experienced ones as well. [cut] @@ -39,11 +39,9 @@ let f = user.sayHi; setTimeout(f, 1000); // lost user context ``` -The method `setTimeout` is a little special: it sets `this=window` for the function call. So for `this.firstName` it tries to get `window.firstName`, which does not exist. In other similar cases as we'll see, usually `this` just becomes `undefined`. +The method `setTimeout` is a little special: it sets `this=window` for the function call. So for `this.firstName` it tries to get `window.firstName`, which does not exist. In other similar cases as we'll see, usually `this` just becomes `undefined`. -The task is quite typical -- we want to pass an object method somewhere else where it will be called. How to make sure that it will be called in the right context? - -There are few ways we can go. +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? ## Solution 1: a wrapper @@ -66,7 +64,7 @@ setTimeout(function() { Now it works, because it receives `user` from the outer lexical environment, and then calls the method normally. -The same function, but shorter: +The same, but shorter: ```js setTimeout(() => user.sayHi(), 1000); // Hello, John! @@ -74,22 +72,41 @@ setTimeout(() => user.sayHi(), 1000); // Hello, John! Looks fine, but a slight vulnerability appears in our code structure. -What is before `setTimeout` triggers (one second delay!) `user` will get another value. Then, suddenly, the it will call the wrong object! +What is before `setTimeout` triggers (there's one second delay!) `user` changes value? Then, suddenly, the it will call the wrong object! -Surely, we could write code more carefully. But it would be better if we could just guarantee the right context, no matter what. + +```js run +let user = { + firstName: "John", + sayHi() { + alert(`Hello, ${this.firstName}!`); + } +}; + +setTimeout(() => user.sayHi(), 1000); + +// ...within 1 second +user = { sayHi() { alert("Another user in setTimeout!"); } }; + +// Another user in setTimeout?!? +``` + +The next solution guarantees that such thing won't happen. ## Solution 2: bind Functions provide a built-in method [bind](mdn:js/Function/bind) that allows to fix `this`. -The syntax is: +The basic syntax is: ```js // more complex syntax will be little later -let bound = func.bind(context); +let boundFunc = func.bind(context); ```` -The result of `func.bind` is a special "exotic object", that is essentially a function, but instead of having its own body, it transparently passes the call to `func` with given arguments and `this=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`. + +In other words, calling `boundFunc` is like `func` with fixed `this`. For instance, here `funcUser` passes a call to `func` with `this=user`: @@ -108,10 +125,9 @@ funcUser(); // John */!* ``` -We can think of `func.bind(user)` as a "bound" variant of `func`, with fixed `this=user`. - -The example below demonstrates that arguments are passed "as is" to `func`: +Here `func.bind(user)` as a "bound variant" of `func`, with fixed `this=user`. +All arguments are passed to the original `func` "as is", for instance: ```js run let user = { @@ -122,9 +138,11 @@ function func(phrase) { alert(phrase + ', ' + this.firstName); } -let funcUser = func.bind(user); // funcUser passes all calls to func with this=user +// bind this to user +let funcUser = func.bind(user); + *!* -funcUser("Hello"); // Hello, John (argument "Hello" is passed as is) +funcUser("Hello"); // Hello, John (argument "Hello" is passed, and this=user) */!* ``` @@ -150,7 +168,7 @@ setTimeout(sayHi, 1000); // Hello, John! 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. -It fixes only `this`, arguments are passed "as is": +Here we can see that arguments are passed "as is", only `this` is fixed by `bind`: ```js run let user = { @@ -186,7 +204,7 @@ Javascript libraries also provide functions for convenient mass binding , e.g. [ Till now we were only talking about binding `this`. Now let's make a step further. -We can bind not only `this`, but also arguments. That's more seldom used, but can also be handy. +We can bind not only `this`, but also arguments. That's rarely done, but sometimes can be handy. The full syntax of `bind`: @@ -204,11 +222,11 @@ function mul(a, b) { } ``` -Let's use `bind` to create a function, doubling the value: +Let's use `bind` to create a function `double` on its base: ```js run *!* -let double = mul.bind(null, 2); +let double = mul.bind(null, 2); */!* alert( double(3) ); // = mul(2, 3) = 6 @@ -220,13 +238,13 @@ The call to `mul.bind(null, 2)` creates a new function `double` that passes call 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 the `this` context. But `bind` requires it first, so we need to pass something like `null`. +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 *!* -let triple = mul.bind(null, 3); +let triple = mul.bind(null, 3); */!* alert( triple(3) ); // = mul(3, 3) = 9 @@ -234,7 +252,7 @@ alert( triple(4) ); // = mul(3, 4) = 12 alert( triple(5) ); // = mul(3, 5) = 15 ``` -Why to make a partial function? +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`. @@ -244,7 +262,7 @@ For instance, we have a function `send(from, to, text)`. Then, inside a `user` o ### Going partial without context -What if we'd like to fix arguments only, but do not touch the 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. @@ -256,7 +274,7 @@ Like this: *!* function partial(func, ...argsBound) { return function(...args) { // (*) - return func.call(this, ...argsBound, ...args); + return func.call(this, ...argsBound, ...args); } } */!* @@ -265,15 +283,16 @@ function partial(func, ...argsBound) { let user = { firstName: "John", say(time, phrase) { - alert(`[${time}] ${phrase}, ${this.firstName}!`); + alert(`[${time}] ${this.firstName}: ${phrase}!`); } }; -user.sayNow = partial(user.say, "10:00"); // fix the first argument +// 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"); +user.sayNow("Hello"); +// Something like: // [10:00] Hello, John! -// translates to: user.say("10:00", "Hello") ``` The result of `partial(func[, arg1, arg2...])` call is a wrapper `(*)` that calls `func` with: @@ -281,20 +300,17 @@ The result of `partial(func[, arg1, arg2...])` call is a wrapper `(*)` that call - Then gives it `...argsBound` -- arguments from the `partial` call (`"10:00"`) - Then gives it `...args` -- arguments given to the wrapper (`"Hello"`) - -In other words, the function gets an unaltered context, then partial-bound arguments, then those that come from the call. - So easy to do it the spread operator, right? -Also we can use [_.partial](https://lodash.com/docs#partial) from lodash library. +Also there's a ready [_.partial](https://lodash.com/docs#partial) implementation from lodash library. -## Currying +## Currying -Sometimes people mix up partial function application mentioned above with another thing named "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)`. -Let's make `curry` function that translates `f(a, b)` into `f(a)(b)`: +Let's make `curry` function that performs currying for binary functions. In other words, it translates `f(a, b)` into `f(a)(b)`: ```js run *!* @@ -317,23 +333,89 @@ let carriedSum = curry(sum); alert( carriedSum(1)(2) ); // 3 ``` -As you can see, the implementation is a series of wrappers. +As you can see, the implementation is a series of wrappers. -- The result of `curry(func)` is a wrapper `function(a)`. +- 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`. -We can make it more universal: +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? + +Advanced currying allows both to keep the function callable normally and to get partials easily. To understand the benefits we definitely need a worthy real-life example. + +For instance, we have the logging function `log(date, importance, message)` that formats and output 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 loose 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. ```js run function curry(func) { return function curried(...args) { if (args.length >= func.length) { - return func.apply(this, args); + return func.apply(this, args); } else { return function(...args2) { - return curried.apply(this, args.concat(args2)); + return curried.apply(this, args.concat(args2)); } } }; @@ -344,101 +426,72 @@ function sum(a, b, c) { return a + b + c; } -let curried = curry(sum); +let curriedSum = curry(sum); +// still callable normally +alert( curried(1, 2, 3) ); // 6 + +// get the partial with curried(1) and call it with 2 other arguments +alert( curried(1)(2,3) ); // 6 + +// full curried form alert( curried(1)(2)(3) ); // 6 ``` -Now it transforms 3-argument `sum` with ease. +The new `curry` may look complicated, but it's actually pretty easy to understand. -The new `curry` is a little more complicated. An attentive look still can make it easy to understand. - -The result of `curry(func)` is a wrapper: +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); + return func.apply(this, args); } else { return function pass(...args2) { // (2) - return curried.apply(this, args.concat(args2)); + return curried.apply(this, args.concat(args2)); } } }; ``` -1. 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. Otherwise, `func` is not called yet. Instead, another wrapper is returned, that will take already-received `args` from the closure and try to invoke `curried` with them plus what it gets. +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 next call becomes `pass(2)`, it takes previous args (`1`), concatenates them with what it got `(2)` and calls `curried(1, 2)` with them together. +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`, current arguments (now `1` and `2`) are retained in the Lexical Environment. -3. Finally, 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. + 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. -We can also use [_.curry](https://lodash.com/docs#curry) from lodash library for the same purpose. - ```smart header="Fixed-length functions only" -The currying process requires the function to have a known fixed number of arguments. +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 also keep the function callable in the multi-argument variant. +But most implementations of currying in Javascript are advanced, as described: they also keep the function callable in the multi-argument variant. ``` -### Currying? What for? +## Summary -Currying allows to get partial functions easily, without breaking normal function runs. +- Method `func.bind(context, ...args)` returns a "bound variant" of function `func` that fixes the context `this` and first arguments if given. -For instance, we have the logging function `log(date, importance, message)` to nicely output that information (and in real-life it has a lot of other useful features): + We may need to fix a context for passing an object method somewhere to be called. For example, to `setTimeout`. -```js -function log(date, importance, message) { - alert(`[${date.getHours()}:${date.getMinutes()}] [${importance}] ${message}`); -} +- When we fix some arguments of an existing function, the resulting (less universal) function is called *a partial*. We saw other ways of making partials than `bind`. -// let's curry it! -log = _.curry(log); + 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. -// still works the normal way -log(new Date(), "DEBUG", "3-arg call"); +- *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. -// but also can call it in curried form: -log(new Date())("DEBUG")("3-arg call"); - -*!* -// let's get a convenience function for today's logs: -let todayLog = log(new Date()); -*/!* - -todayLog("INFO", "2-arg call"); - -// let's get a convenience function for today's debug messages: -*!* -let todayDebug = todayLog("DEBUG"); -*/!* - -todayDebug("1-arg call"); -``` - -## Summary [todo] - -To safely pass an object method to `setTimeout`, we can bind the context to it. - -The syntax: - -```js -let bound = func.bind(context, arg1, arg2...) -``` - -The result is an "exotic object" that passes all calls to `func`, fixing context and arguments (if provided). - -We can use it to fix the context (most often case), or also some of the arguments. + Currying is convenient when we want to have easy partials. We saw an example with logging: the universal function `log(date, importance, message)` after currying gives us partials when called with one argument like `log(date)` or two arguments `log(date, importance)`. diff --git a/1-js/8-more-functions/08-bind/head.html b/1-js/8-more-functions/09-bind/head.html similarity index 100% rename from 1-js/8-more-functions/08-bind/head.html rename to 1-js/8-more-functions/09-bind/head.html diff --git a/1-js/5-data-types/12-property-flags-descriptors/article.md b/1-js/9-object-inheritance/01-property-flags-descriptors/article.md similarity index 100% rename from 1-js/5-data-types/12-property-flags-descriptors/article.md rename to 1-js/9-object-inheritance/01-property-flags-descriptors/article.md diff --git a/1-js/5-data-types/13-property-accessors/article.md b/1-js/9-object-inheritance/02-property-accessors/article.md similarity index 100% rename from 1-js/5-data-types/13-property-accessors/article.md rename to 1-js/9-object-inheritance/02-property-accessors/article.md diff --git a/1-js/9-object-inheritance/01-prototype/1-property-after-delete/solution.md b/1-js/9-object-inheritance/03-prototype/1-property-after-delete/solution.md similarity index 100% rename from 1-js/9-object-inheritance/01-prototype/1-property-after-delete/solution.md rename to 1-js/9-object-inheritance/03-prototype/1-property-after-delete/solution.md diff --git a/1-js/9-object-inheritance/01-prototype/1-property-after-delete/task.md b/1-js/9-object-inheritance/03-prototype/1-property-after-delete/task.md similarity index 100% rename from 1-js/9-object-inheritance/01-prototype/1-property-after-delete/task.md rename to 1-js/9-object-inheritance/03-prototype/1-property-after-delete/task.md diff --git a/1-js/9-object-inheritance/01-prototype/2-search-algorithm/solution.md b/1-js/9-object-inheritance/03-prototype/2-search-algorithm/solution.md similarity index 100% rename from 1-js/9-object-inheritance/01-prototype/2-search-algorithm/solution.md rename to 1-js/9-object-inheritance/03-prototype/2-search-algorithm/solution.md diff --git a/1-js/9-object-inheritance/01-prototype/2-search-algorithm/task.md b/1-js/9-object-inheritance/03-prototype/2-search-algorithm/task.md similarity index 100% rename from 1-js/9-object-inheritance/01-prototype/2-search-algorithm/task.md rename to 1-js/9-object-inheritance/03-prototype/2-search-algorithm/task.md diff --git a/1-js/9-object-inheritance/01-prototype/3-proto-and-this/solution.md b/1-js/9-object-inheritance/03-prototype/3-proto-and-this/solution.md similarity index 100% rename from 1-js/9-object-inheritance/01-prototype/3-proto-and-this/solution.md rename to 1-js/9-object-inheritance/03-prototype/3-proto-and-this/solution.md diff --git a/1-js/9-object-inheritance/01-prototype/3-proto-and-this/task.md b/1-js/9-object-inheritance/03-prototype/3-proto-and-this/task.md similarity index 100% rename from 1-js/9-object-inheritance/01-prototype/3-proto-and-this/task.md rename to 1-js/9-object-inheritance/03-prototype/3-proto-and-this/task.md diff --git a/1-js/9-object-inheritance/01-prototype/4-hamster-proto/solution.md b/1-js/9-object-inheritance/03-prototype/4-hamster-proto/solution.md similarity index 100% rename from 1-js/9-object-inheritance/01-prototype/4-hamster-proto/solution.md rename to 1-js/9-object-inheritance/03-prototype/4-hamster-proto/solution.md diff --git a/1-js/9-object-inheritance/01-prototype/4-hamster-proto/task.md b/1-js/9-object-inheritance/03-prototype/4-hamster-proto/task.md similarity index 100% rename from 1-js/9-object-inheritance/01-prototype/4-hamster-proto/task.md rename to 1-js/9-object-inheritance/03-prototype/4-hamster-proto/task.md diff --git a/1-js/9-object-inheritance/01-prototype/article.md b/1-js/9-object-inheritance/03-prototype/article.md similarity index 100% rename from 1-js/9-object-inheritance/01-prototype/article.md rename to 1-js/9-object-inheritance/03-prototype/article.md diff --git a/1-js/9-object-inheritance/01-prototype/proto-animal-rabbit-chain.png b/1-js/9-object-inheritance/03-prototype/proto-animal-rabbit-chain.png similarity index 100% rename from 1-js/9-object-inheritance/01-prototype/proto-animal-rabbit-chain.png rename to 1-js/9-object-inheritance/03-prototype/proto-animal-rabbit-chain.png diff --git a/1-js/9-object-inheritance/01-prototype/proto-animal-rabbit-chain@2x.png b/1-js/9-object-inheritance/03-prototype/proto-animal-rabbit-chain@2x.png similarity index 100% rename from 1-js/9-object-inheritance/01-prototype/proto-animal-rabbit-chain@2x.png rename to 1-js/9-object-inheritance/03-prototype/proto-animal-rabbit-chain@2x.png diff --git a/1-js/9-object-inheritance/01-prototype/proto-animal-rabbit-walk-2.png b/1-js/9-object-inheritance/03-prototype/proto-animal-rabbit-walk-2.png similarity index 100% rename from 1-js/9-object-inheritance/01-prototype/proto-animal-rabbit-walk-2.png rename to 1-js/9-object-inheritance/03-prototype/proto-animal-rabbit-walk-2.png diff --git a/1-js/9-object-inheritance/01-prototype/proto-animal-rabbit-walk-2@2x.png b/1-js/9-object-inheritance/03-prototype/proto-animal-rabbit-walk-2@2x.png similarity index 100% rename from 1-js/9-object-inheritance/01-prototype/proto-animal-rabbit-walk-2@2x.png rename to 1-js/9-object-inheritance/03-prototype/proto-animal-rabbit-walk-2@2x.png diff --git a/1-js/9-object-inheritance/01-prototype/proto-animal-rabbit-walk-3.png b/1-js/9-object-inheritance/03-prototype/proto-animal-rabbit-walk-3.png similarity index 100% rename from 1-js/9-object-inheritance/01-prototype/proto-animal-rabbit-walk-3.png rename to 1-js/9-object-inheritance/03-prototype/proto-animal-rabbit-walk-3.png diff --git a/1-js/9-object-inheritance/01-prototype/proto-animal-rabbit-walk-3@2x.png b/1-js/9-object-inheritance/03-prototype/proto-animal-rabbit-walk-3@2x.png similarity index 100% rename from 1-js/9-object-inheritance/01-prototype/proto-animal-rabbit-walk-3@2x.png rename to 1-js/9-object-inheritance/03-prototype/proto-animal-rabbit-walk-3@2x.png diff --git a/1-js/9-object-inheritance/01-prototype/proto-animal-rabbit-walk.png b/1-js/9-object-inheritance/03-prototype/proto-animal-rabbit-walk.png similarity index 100% rename from 1-js/9-object-inheritance/01-prototype/proto-animal-rabbit-walk.png rename to 1-js/9-object-inheritance/03-prototype/proto-animal-rabbit-walk.png diff --git a/1-js/9-object-inheritance/01-prototype/proto-animal-rabbit-walk@2x.png b/1-js/9-object-inheritance/03-prototype/proto-animal-rabbit-walk@2x.png similarity index 100% rename from 1-js/9-object-inheritance/01-prototype/proto-animal-rabbit-walk@2x.png rename to 1-js/9-object-inheritance/03-prototype/proto-animal-rabbit-walk@2x.png diff --git a/1-js/9-object-inheritance/01-prototype/proto-animal-rabbit.png b/1-js/9-object-inheritance/03-prototype/proto-animal-rabbit.png similarity index 100% rename from 1-js/9-object-inheritance/01-prototype/proto-animal-rabbit.png rename to 1-js/9-object-inheritance/03-prototype/proto-animal-rabbit.png diff --git a/1-js/9-object-inheritance/01-prototype/proto-animal-rabbit@2x.png b/1-js/9-object-inheritance/03-prototype/proto-animal-rabbit@2x.png similarity index 100% rename from 1-js/9-object-inheritance/01-prototype/proto-animal-rabbit@2x.png rename to 1-js/9-object-inheritance/03-prototype/proto-animal-rabbit@2x.png diff --git a/1-js/9-object-inheritance/01-prototype/proto-user-admin.png b/1-js/9-object-inheritance/03-prototype/proto-user-admin.png similarity index 100% rename from 1-js/9-object-inheritance/01-prototype/proto-user-admin.png rename to 1-js/9-object-inheritance/03-prototype/proto-user-admin.png diff --git a/1-js/9-object-inheritance/01-prototype/proto-user-admin@2x.png b/1-js/9-object-inheritance/03-prototype/proto-user-admin@2x.png similarity index 100% rename from 1-js/9-object-inheritance/01-prototype/proto-user-admin@2x.png rename to 1-js/9-object-inheritance/03-prototype/proto-user-admin@2x.png diff --git a/1-js/9-object-inheritance/02-managing-prototype/1-prototype-after-new/solution.md b/1-js/9-object-inheritance/04-managing-prototype/1-prototype-after-new/solution.md similarity index 100% rename from 1-js/9-object-inheritance/02-managing-prototype/1-prototype-after-new/solution.md rename to 1-js/9-object-inheritance/04-managing-prototype/1-prototype-after-new/solution.md diff --git a/1-js/9-object-inheritance/02-managing-prototype/1-prototype-after-new/task.md b/1-js/9-object-inheritance/04-managing-prototype/1-prototype-after-new/task.md similarity index 100% rename from 1-js/9-object-inheritance/02-managing-prototype/1-prototype-after-new/task.md rename to 1-js/9-object-inheritance/04-managing-prototype/1-prototype-after-new/task.md diff --git a/1-js/9-object-inheritance/02-managing-prototype/2-dictionary-tostring/solution.md b/1-js/9-object-inheritance/04-managing-prototype/2-dictionary-tostring/solution.md similarity index 100% rename from 1-js/9-object-inheritance/02-managing-prototype/2-dictionary-tostring/solution.md rename to 1-js/9-object-inheritance/04-managing-prototype/2-dictionary-tostring/solution.md diff --git a/1-js/9-object-inheritance/02-managing-prototype/2-dictionary-tostring/task.md b/1-js/9-object-inheritance/04-managing-prototype/2-dictionary-tostring/task.md similarity index 100% rename from 1-js/9-object-inheritance/02-managing-prototype/2-dictionary-tostring/task.md rename to 1-js/9-object-inheritance/04-managing-prototype/2-dictionary-tostring/task.md diff --git a/1-js/9-object-inheritance/02-managing-prototype/3-compare-calls/solution.md b/1-js/9-object-inheritance/04-managing-prototype/3-compare-calls/solution.md similarity index 100% rename from 1-js/9-object-inheritance/02-managing-prototype/3-compare-calls/solution.md rename to 1-js/9-object-inheritance/04-managing-prototype/3-compare-calls/solution.md diff --git a/1-js/9-object-inheritance/02-managing-prototype/3-compare-calls/task.md b/1-js/9-object-inheritance/04-managing-prototype/3-compare-calls/task.md similarity index 100% rename from 1-js/9-object-inheritance/02-managing-prototype/3-compare-calls/task.md rename to 1-js/9-object-inheritance/04-managing-prototype/3-compare-calls/task.md diff --git a/1-js/9-object-inheritance/02-managing-prototype/4-new-object-same-constructor/solution.md b/1-js/9-object-inheritance/04-managing-prototype/4-new-object-same-constructor/solution.md similarity index 100% rename from 1-js/9-object-inheritance/02-managing-prototype/4-new-object-same-constructor/solution.md rename to 1-js/9-object-inheritance/04-managing-prototype/4-new-object-same-constructor/solution.md diff --git a/1-js/9-object-inheritance/02-managing-prototype/4-new-object-same-constructor/task.md b/1-js/9-object-inheritance/04-managing-prototype/4-new-object-same-constructor/task.md similarity index 100% rename from 1-js/9-object-inheritance/02-managing-prototype/4-new-object-same-constructor/task.md rename to 1-js/9-object-inheritance/04-managing-prototype/4-new-object-same-constructor/task.md diff --git a/1-js/9-object-inheritance/02-managing-prototype/article.md b/1-js/9-object-inheritance/04-managing-prototype/article.md similarity index 100% rename from 1-js/9-object-inheritance/02-managing-prototype/article.md rename to 1-js/9-object-inheritance/04-managing-prototype/article.md diff --git a/1-js/9-object-inheritance/02-managing-prototype/function-prototype-constructor.png b/1-js/9-object-inheritance/04-managing-prototype/function-prototype-constructor.png similarity index 100% rename from 1-js/9-object-inheritance/02-managing-prototype/function-prototype-constructor.png rename to 1-js/9-object-inheritance/04-managing-prototype/function-prototype-constructor.png diff --git a/1-js/9-object-inheritance/02-managing-prototype/function-prototype-constructor@2x.png b/1-js/9-object-inheritance/04-managing-prototype/function-prototype-constructor@2x.png similarity index 100% rename from 1-js/9-object-inheritance/02-managing-prototype/function-prototype-constructor@2x.png rename to 1-js/9-object-inheritance/04-managing-prototype/function-prototype-constructor@2x.png diff --git a/1-js/9-object-inheritance/02-managing-prototype/native-prototypes-array-tostring.png b/1-js/9-object-inheritance/04-managing-prototype/native-prototypes-array-tostring.png similarity index 100% rename from 1-js/9-object-inheritance/02-managing-prototype/native-prototypes-array-tostring.png rename to 1-js/9-object-inheritance/04-managing-prototype/native-prototypes-array-tostring.png diff --git a/1-js/9-object-inheritance/02-managing-prototype/native-prototypes-array-tostring@2x.png b/1-js/9-object-inheritance/04-managing-prototype/native-prototypes-array-tostring@2x.png similarity index 100% rename from 1-js/9-object-inheritance/02-managing-prototype/native-prototypes-array-tostring@2x.png rename to 1-js/9-object-inheritance/04-managing-prototype/native-prototypes-array-tostring@2x.png diff --git a/1-js/9-object-inheritance/02-managing-prototype/native-prototypes-classes.png b/1-js/9-object-inheritance/04-managing-prototype/native-prototypes-classes.png similarity index 100% rename from 1-js/9-object-inheritance/02-managing-prototype/native-prototypes-classes.png rename to 1-js/9-object-inheritance/04-managing-prototype/native-prototypes-classes.png diff --git a/1-js/9-object-inheritance/02-managing-prototype/native-prototypes-classes@2x.png b/1-js/9-object-inheritance/04-managing-prototype/native-prototypes-classes@2x.png similarity index 100% rename from 1-js/9-object-inheritance/02-managing-prototype/native-prototypes-classes@2x.png rename to 1-js/9-object-inheritance/04-managing-prototype/native-prototypes-classes@2x.png diff --git a/1-js/9-object-inheritance/02-managing-prototype/object-prototype-1.png b/1-js/9-object-inheritance/04-managing-prototype/object-prototype-1.png similarity index 100% rename from 1-js/9-object-inheritance/02-managing-prototype/object-prototype-1.png rename to 1-js/9-object-inheritance/04-managing-prototype/object-prototype-1.png diff --git a/1-js/9-object-inheritance/02-managing-prototype/object-prototype-1@2x.png b/1-js/9-object-inheritance/04-managing-prototype/object-prototype-1@2x.png similarity index 100% rename from 1-js/9-object-inheritance/02-managing-prototype/object-prototype-1@2x.png rename to 1-js/9-object-inheritance/04-managing-prototype/object-prototype-1@2x.png diff --git a/1-js/9-object-inheritance/02-managing-prototype/object-prototype-2.png b/1-js/9-object-inheritance/04-managing-prototype/object-prototype-2.png similarity index 100% rename from 1-js/9-object-inheritance/02-managing-prototype/object-prototype-2.png rename to 1-js/9-object-inheritance/04-managing-prototype/object-prototype-2.png diff --git a/1-js/9-object-inheritance/02-managing-prototype/object-prototype-2@2x.png b/1-js/9-object-inheritance/04-managing-prototype/object-prototype-2@2x.png similarity index 100% rename from 1-js/9-object-inheritance/02-managing-prototype/object-prototype-2@2x.png rename to 1-js/9-object-inheritance/04-managing-prototype/object-prototype-2@2x.png diff --git a/1-js/9-object-inheritance/02-managing-prototype/object-prototype-null.png b/1-js/9-object-inheritance/04-managing-prototype/object-prototype-null.png similarity index 100% rename from 1-js/9-object-inheritance/02-managing-prototype/object-prototype-null.png rename to 1-js/9-object-inheritance/04-managing-prototype/object-prototype-null.png diff --git a/1-js/9-object-inheritance/02-managing-prototype/object-prototype-null@2x.png b/1-js/9-object-inheritance/04-managing-prototype/object-prototype-null@2x.png similarity index 100% rename from 1-js/9-object-inheritance/02-managing-prototype/object-prototype-null@2x.png rename to 1-js/9-object-inheritance/04-managing-prototype/object-prototype-null@2x.png diff --git a/1-js/9-object-inheritance/02-managing-prototype/object-prototype.png b/1-js/9-object-inheritance/04-managing-prototype/object-prototype.png similarity index 100% rename from 1-js/9-object-inheritance/02-managing-prototype/object-prototype.png rename to 1-js/9-object-inheritance/04-managing-prototype/object-prototype.png diff --git a/1-js/9-object-inheritance/02-managing-prototype/object-prototype@2x.png b/1-js/9-object-inheritance/04-managing-prototype/object-prototype@2x.png similarity index 100% rename from 1-js/9-object-inheritance/02-managing-prototype/object-prototype@2x.png rename to 1-js/9-object-inheritance/04-managing-prototype/object-prototype@2x.png diff --git a/1-js/9-object-inheritance/02-managing-prototype/proto-constructor-animal-rabbit.png b/1-js/9-object-inheritance/04-managing-prototype/proto-constructor-animal-rabbit.png similarity index 100% rename from 1-js/9-object-inheritance/02-managing-prototype/proto-constructor-animal-rabbit.png rename to 1-js/9-object-inheritance/04-managing-prototype/proto-constructor-animal-rabbit.png diff --git a/1-js/9-object-inheritance/02-managing-prototype/proto-constructor-animal-rabbit@2x.png b/1-js/9-object-inheritance/04-managing-prototype/proto-constructor-animal-rabbit@2x.png similarity index 100% rename from 1-js/9-object-inheritance/02-managing-prototype/proto-constructor-animal-rabbit@2x.png rename to 1-js/9-object-inheritance/04-managing-prototype/proto-constructor-animal-rabbit@2x.png diff --git a/1-js/9-object-inheritance/02-managing-prototype/rabbit-animal-object.png b/1-js/9-object-inheritance/04-managing-prototype/rabbit-animal-object.png similarity index 100% rename from 1-js/9-object-inheritance/02-managing-prototype/rabbit-animal-object.png rename to 1-js/9-object-inheritance/04-managing-prototype/rabbit-animal-object.png diff --git a/1-js/9-object-inheritance/02-managing-prototype/rabbit-animal-object@2x.png b/1-js/9-object-inheritance/04-managing-prototype/rabbit-animal-object@2x.png similarity index 100% rename from 1-js/9-object-inheritance/02-managing-prototype/rabbit-animal-object@2x.png rename to 1-js/9-object-inheritance/04-managing-prototype/rabbit-animal-object@2x.png diff --git a/1-js/9-object-inheritance/02-managing-prototype/rabbit-prototype-constructor.png b/1-js/9-object-inheritance/04-managing-prototype/rabbit-prototype-constructor.png similarity index 100% rename from 1-js/9-object-inheritance/02-managing-prototype/rabbit-prototype-constructor.png rename to 1-js/9-object-inheritance/04-managing-prototype/rabbit-prototype-constructor.png diff --git a/1-js/9-object-inheritance/02-managing-prototype/rabbit-prototype-constructor@2x.png b/1-js/9-object-inheritance/04-managing-prototype/rabbit-prototype-constructor@2x.png similarity index 100% rename from 1-js/9-object-inheritance/02-managing-prototype/rabbit-prototype-constructor@2x.png rename to 1-js/9-object-inheritance/04-managing-prototype/rabbit-prototype-constructor@2x.png diff --git a/1-js/9-object-inheritance/03-native-prototypes/1-defer-to-prototype/solution.md b/1-js/9-object-inheritance/05-native-prototypes/1-defer-to-prototype/solution.md similarity index 100% rename from 1-js/9-object-inheritance/03-native-prototypes/1-defer-to-prototype/solution.md rename to 1-js/9-object-inheritance/05-native-prototypes/1-defer-to-prototype/solution.md diff --git a/1-js/9-object-inheritance/03-native-prototypes/1-defer-to-prototype/task.md b/1-js/9-object-inheritance/05-native-prototypes/1-defer-to-prototype/task.md similarity index 100% rename from 1-js/9-object-inheritance/03-native-prototypes/1-defer-to-prototype/task.md rename to 1-js/9-object-inheritance/05-native-prototypes/1-defer-to-prototype/task.md diff --git a/1-js/9-object-inheritance/03-native-prototypes/2-defer-to-prototype-extended/solution.md b/1-js/9-object-inheritance/05-native-prototypes/2-defer-to-prototype-extended/solution.md similarity index 100% rename from 1-js/9-object-inheritance/03-native-prototypes/2-defer-to-prototype-extended/solution.md rename to 1-js/9-object-inheritance/05-native-prototypes/2-defer-to-prototype-extended/solution.md diff --git a/1-js/9-object-inheritance/03-native-prototypes/2-defer-to-prototype-extended/task.md b/1-js/9-object-inheritance/05-native-prototypes/2-defer-to-prototype-extended/task.md similarity index 100% rename from 1-js/9-object-inheritance/03-native-prototypes/2-defer-to-prototype-extended/task.md rename to 1-js/9-object-inheritance/05-native-prototypes/2-defer-to-prototype-extended/task.md diff --git a/1-js/9-object-inheritance/03-native-prototypes/article.md b/1-js/9-object-inheritance/05-native-prototypes/article.md similarity index 100% rename from 1-js/9-object-inheritance/03-native-prototypes/article.md rename to 1-js/9-object-inheritance/05-native-prototypes/article.md diff --git a/1-js/9-object-inheritance/03-native-prototypes/native-prototype-object.png b/1-js/9-object-inheritance/05-native-prototypes/native-prototype-object.png similarity index 100% rename from 1-js/9-object-inheritance/03-native-prototypes/native-prototype-object.png rename to 1-js/9-object-inheritance/05-native-prototypes/native-prototype-object.png diff --git a/1-js/9-object-inheritance/03-native-prototypes/native-prototypes-array-tostring.png b/1-js/9-object-inheritance/05-native-prototypes/native-prototypes-array-tostring.png similarity index 100% rename from 1-js/9-object-inheritance/03-native-prototypes/native-prototypes-array-tostring.png rename to 1-js/9-object-inheritance/05-native-prototypes/native-prototypes-array-tostring.png diff --git a/1-js/9-object-inheritance/03-native-prototypes/native-prototypes-array-tostring@2x.png b/1-js/9-object-inheritance/05-native-prototypes/native-prototypes-array-tostring@2x.png similarity index 100% rename from 1-js/9-object-inheritance/03-native-prototypes/native-prototypes-array-tostring@2x.png rename to 1-js/9-object-inheritance/05-native-prototypes/native-prototypes-array-tostring@2x.png diff --git a/1-js/9-object-inheritance/03-native-prototypes/native-prototypes-classes.png b/1-js/9-object-inheritance/05-native-prototypes/native-prototypes-classes.png similarity index 100% rename from 1-js/9-object-inheritance/03-native-prototypes/native-prototypes-classes.png rename to 1-js/9-object-inheritance/05-native-prototypes/native-prototypes-classes.png diff --git a/1-js/9-object-inheritance/03-native-prototypes/native-prototypes-classes@2x.png b/1-js/9-object-inheritance/05-native-prototypes/native-prototypes-classes@2x.png similarity index 100% rename from 1-js/9-object-inheritance/03-native-prototypes/native-prototypes-classes@2x.png rename to 1-js/9-object-inheritance/05-native-prototypes/native-prototypes-classes@2x.png diff --git a/1-js/9-object-inheritance/03-native-prototypes/native-prototypes-object.png b/1-js/9-object-inheritance/05-native-prototypes/native-prototypes-object.png similarity index 100% rename from 1-js/9-object-inheritance/03-native-prototypes/native-prototypes-object.png rename to 1-js/9-object-inheritance/05-native-prototypes/native-prototypes-object.png diff --git a/1-js/9-object-inheritance/03-native-prototypes/native-prototypes-object@2x.png b/1-js/9-object-inheritance/05-native-prototypes/native-prototypes-object@2x.png similarity index 100% rename from 1-js/9-object-inheritance/03-native-prototypes/native-prototypes-object@2x.png rename to 1-js/9-object-inheritance/05-native-prototypes/native-prototypes-object@2x.png diff --git a/1-js/9-object-inheritance/04-class-patterns/article.md b/1-js/9-object-inheritance/06-class-patterns/article.md similarity index 100% rename from 1-js/9-object-inheritance/04-class-patterns/article.md rename to 1-js/9-object-inheritance/06-class-patterns/article.md diff --git a/1-js/9-object-inheritance/04-class-patterns/class-inheritance-rabbit-animal-2.png b/1-js/9-object-inheritance/06-class-patterns/class-inheritance-rabbit-animal-2.png similarity index 100% rename from 1-js/9-object-inheritance/04-class-patterns/class-inheritance-rabbit-animal-2.png rename to 1-js/9-object-inheritance/06-class-patterns/class-inheritance-rabbit-animal-2.png diff --git a/1-js/9-object-inheritance/04-class-patterns/class-inheritance-rabbit-animal-2@2x.png b/1-js/9-object-inheritance/06-class-patterns/class-inheritance-rabbit-animal-2@2x.png similarity index 100% rename from 1-js/9-object-inheritance/04-class-patterns/class-inheritance-rabbit-animal-2@2x.png rename to 1-js/9-object-inheritance/06-class-patterns/class-inheritance-rabbit-animal-2@2x.png diff --git a/1-js/9-object-inheritance/04-class-patterns/class-inheritance-rabbit-animal.png b/1-js/9-object-inheritance/06-class-patterns/class-inheritance-rabbit-animal.png similarity index 100% rename from 1-js/9-object-inheritance/04-class-patterns/class-inheritance-rabbit-animal.png rename to 1-js/9-object-inheritance/06-class-patterns/class-inheritance-rabbit-animal.png diff --git a/1-js/9-object-inheritance/04-class-patterns/class-inheritance-rabbit-animal@2x.png b/1-js/9-object-inheritance/06-class-patterns/class-inheritance-rabbit-animal@2x.png similarity index 100% rename from 1-js/9-object-inheritance/04-class-patterns/class-inheritance-rabbit-animal@2x.png rename to 1-js/9-object-inheritance/06-class-patterns/class-inheritance-rabbit-animal@2x.png diff --git a/1-js/9-object-inheritance/05-class/animal-rabbit-static.png b/1-js/9-object-inheritance/07-class/animal-rabbit-static.png similarity index 100% rename from 1-js/9-object-inheritance/05-class/animal-rabbit-static.png rename to 1-js/9-object-inheritance/07-class/animal-rabbit-static.png diff --git a/1-js/9-object-inheritance/05-class/animal-rabbit-static@2x.png b/1-js/9-object-inheritance/07-class/animal-rabbit-static@2x.png similarity index 100% rename from 1-js/9-object-inheritance/05-class/animal-rabbit-static@2x.png rename to 1-js/9-object-inheritance/07-class/animal-rabbit-static@2x.png diff --git a/1-js/9-object-inheritance/05-class/article.md b/1-js/9-object-inheritance/07-class/article.md similarity index 100% rename from 1-js/9-object-inheritance/05-class/article.md rename to 1-js/9-object-inheritance/07-class/article.md diff --git a/1-js/9-object-inheritance/05-class/class-user.png b/1-js/9-object-inheritance/07-class/class-user.png similarity index 100% rename from 1-js/9-object-inheritance/05-class/class-user.png rename to 1-js/9-object-inheritance/07-class/class-user.png diff --git a/1-js/9-object-inheritance/05-class/class-user@2x.png b/1-js/9-object-inheritance/07-class/class-user@2x.png similarity index 100% rename from 1-js/9-object-inheritance/05-class/class-user@2x.png rename to 1-js/9-object-inheritance/07-class/class-user@2x.png diff --git a/1-js/9-object-inheritance/05-class/object-date-inheritance.png b/1-js/9-object-inheritance/07-class/object-date-inheritance.png similarity index 100% rename from 1-js/9-object-inheritance/05-class/object-date-inheritance.png rename to 1-js/9-object-inheritance/07-class/object-date-inheritance.png diff --git a/1-js/9-object-inheritance/05-class/object-date-inheritance@2x.png b/1-js/9-object-inheritance/07-class/object-date-inheritance@2x.png similarity index 100% rename from 1-js/9-object-inheritance/05-class/object-date-inheritance@2x.png rename to 1-js/9-object-inheritance/07-class/object-date-inheritance@2x.png diff --git a/1-js/9-object-inheritance/05-class/this-super-loop.png b/1-js/9-object-inheritance/07-class/this-super-loop.png similarity index 100% rename from 1-js/9-object-inheritance/05-class/this-super-loop.png rename to 1-js/9-object-inheritance/07-class/this-super-loop.png diff --git a/1-js/9-object-inheritance/05-class/this-super-loop@2x.png b/1-js/9-object-inheritance/07-class/this-super-loop@2x.png similarity index 100% rename from 1-js/9-object-inheritance/05-class/this-super-loop@2x.png rename to 1-js/9-object-inheritance/07-class/this-super-loop@2x.png diff --git a/1-js/9-object-inheritance/15-class-inheritance/1-inheritance-error-assign/solution.md b/1-js/9-object-inheritance/08-class-inheritance/1-inheritance-error-assign/solution.md similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/1-inheritance-error-assign/solution.md rename to 1-js/9-object-inheritance/08-class-inheritance/1-inheritance-error-assign/solution.md diff --git a/1-js/9-object-inheritance/15-class-inheritance/1-inheritance-error-assign/task.md b/1-js/9-object-inheritance/08-class-inheritance/1-inheritance-error-assign/task.md similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/1-inheritance-error-assign/task.md rename to 1-js/9-object-inheritance/08-class-inheritance/1-inheritance-error-assign/task.md diff --git a/1-js/9-object-inheritance/15-class-inheritance/2-inheritance-error-constructor/solution.md b/1-js/9-object-inheritance/08-class-inheritance/2-inheritance-error-constructor/solution.md similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/2-inheritance-error-constructor/solution.md rename to 1-js/9-object-inheritance/08-class-inheritance/2-inheritance-error-constructor/solution.md diff --git a/1-js/9-object-inheritance/15-class-inheritance/2-inheritance-error-constructor/task.md b/1-js/9-object-inheritance/08-class-inheritance/2-inheritance-error-constructor/task.md similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/2-inheritance-error-constructor/task.md rename to 1-js/9-object-inheritance/08-class-inheritance/2-inheritance-error-constructor/task.md diff --git a/1-js/9-object-inheritance/15-class-inheritance/3-clock-class/clock.js b/1-js/9-object-inheritance/08-class-inheritance/3-clock-class/clock.js similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/3-clock-class/clock.js rename to 1-js/9-object-inheritance/08-class-inheritance/3-clock-class/clock.js diff --git a/1-js/9-object-inheritance/15-class-inheritance/3-clock-class/solution.md b/1-js/9-object-inheritance/08-class-inheritance/3-clock-class/solution.md similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/3-clock-class/solution.md rename to 1-js/9-object-inheritance/08-class-inheritance/3-clock-class/solution.md diff --git a/1-js/9-object-inheritance/15-class-inheritance/3-clock-class/solution.view/clock.js b/1-js/9-object-inheritance/08-class-inheritance/3-clock-class/solution.view/clock.js similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/3-clock-class/solution.view/clock.js rename to 1-js/9-object-inheritance/08-class-inheritance/3-clock-class/solution.view/clock.js diff --git a/1-js/9-object-inheritance/15-class-inheritance/3-clock-class/solution.view/index.html b/1-js/9-object-inheritance/08-class-inheritance/3-clock-class/solution.view/index.html similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/3-clock-class/solution.view/index.html rename to 1-js/9-object-inheritance/08-class-inheritance/3-clock-class/solution.view/index.html diff --git a/1-js/9-object-inheritance/15-class-inheritance/3-clock-class/source.view/clock.js b/1-js/9-object-inheritance/08-class-inheritance/3-clock-class/source.view/clock.js similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/3-clock-class/source.view/clock.js rename to 1-js/9-object-inheritance/08-class-inheritance/3-clock-class/source.view/clock.js diff --git a/1-js/9-object-inheritance/15-class-inheritance/3-clock-class/source.view/index.html b/1-js/9-object-inheritance/08-class-inheritance/3-clock-class/source.view/index.html similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/3-clock-class/source.view/index.html rename to 1-js/9-object-inheritance/08-class-inheritance/3-clock-class/source.view/index.html diff --git a/1-js/9-object-inheritance/15-class-inheritance/3-clock-class/task.md b/1-js/9-object-inheritance/08-class-inheritance/3-clock-class/task.md similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/3-clock-class/task.md rename to 1-js/9-object-inheritance/08-class-inheritance/3-clock-class/task.md diff --git a/1-js/9-object-inheritance/15-class-inheritance/4-clock-class-extended/extended-clock.js b/1-js/9-object-inheritance/08-class-inheritance/4-clock-class-extended/extended-clock.js similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/4-clock-class-extended/extended-clock.js rename to 1-js/9-object-inheritance/08-class-inheritance/4-clock-class-extended/extended-clock.js diff --git a/1-js/9-object-inheritance/15-class-inheritance/4-clock-class-extended/solution.md b/1-js/9-object-inheritance/08-class-inheritance/4-clock-class-extended/solution.md similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/4-clock-class-extended/solution.md rename to 1-js/9-object-inheritance/08-class-inheritance/4-clock-class-extended/solution.md diff --git a/1-js/9-object-inheritance/15-class-inheritance/4-clock-class-extended/solution.view/clock.js b/1-js/9-object-inheritance/08-class-inheritance/4-clock-class-extended/solution.view/clock.js similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/4-clock-class-extended/solution.view/clock.js rename to 1-js/9-object-inheritance/08-class-inheritance/4-clock-class-extended/solution.view/clock.js diff --git a/1-js/9-object-inheritance/15-class-inheritance/4-clock-class-extended/solution.view/extended-clock.js b/1-js/9-object-inheritance/08-class-inheritance/4-clock-class-extended/solution.view/extended-clock.js similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/4-clock-class-extended/solution.view/extended-clock.js rename to 1-js/9-object-inheritance/08-class-inheritance/4-clock-class-extended/solution.view/extended-clock.js diff --git a/1-js/9-object-inheritance/15-class-inheritance/4-clock-class-extended/solution.view/index.html b/1-js/9-object-inheritance/08-class-inheritance/4-clock-class-extended/solution.view/index.html similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/4-clock-class-extended/solution.view/index.html rename to 1-js/9-object-inheritance/08-class-inheritance/4-clock-class-extended/solution.view/index.html diff --git a/1-js/9-object-inheritance/15-class-inheritance/4-clock-class-extended/source.view/clock.js b/1-js/9-object-inheritance/08-class-inheritance/4-clock-class-extended/source.view/clock.js similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/4-clock-class-extended/source.view/clock.js rename to 1-js/9-object-inheritance/08-class-inheritance/4-clock-class-extended/source.view/clock.js diff --git a/1-js/9-object-inheritance/15-class-inheritance/4-clock-class-extended/source.view/extended-clock.js b/1-js/9-object-inheritance/08-class-inheritance/4-clock-class-extended/source.view/extended-clock.js similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/4-clock-class-extended/source.view/extended-clock.js rename to 1-js/9-object-inheritance/08-class-inheritance/4-clock-class-extended/source.view/extended-clock.js diff --git a/1-js/9-object-inheritance/15-class-inheritance/4-clock-class-extended/source.view/index.html b/1-js/9-object-inheritance/08-class-inheritance/4-clock-class-extended/source.view/index.html similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/4-clock-class-extended/source.view/index.html rename to 1-js/9-object-inheritance/08-class-inheritance/4-clock-class-extended/source.view/index.html diff --git a/1-js/9-object-inheritance/15-class-inheritance/4-clock-class-extended/task.md b/1-js/9-object-inheritance/08-class-inheritance/4-clock-class-extended/task.md similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/4-clock-class-extended/task.md rename to 1-js/9-object-inheritance/08-class-inheritance/4-clock-class-extended/task.md diff --git a/1-js/9-object-inheritance/15-class-inheritance/5-menu-timer-animated/solution.md b/1-js/9-object-inheritance/08-class-inheritance/5-menu-timer-animated/solution.md similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/5-menu-timer-animated/solution.md rename to 1-js/9-object-inheritance/08-class-inheritance/5-menu-timer-animated/solution.md diff --git a/1-js/9-object-inheritance/15-class-inheritance/5-menu-timer-animated/solution.view/index.html b/1-js/9-object-inheritance/08-class-inheritance/5-menu-timer-animated/solution.view/index.html similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/5-menu-timer-animated/solution.view/index.html rename to 1-js/9-object-inheritance/08-class-inheritance/5-menu-timer-animated/solution.view/index.html diff --git a/1-js/9-object-inheritance/15-class-inheritance/5-menu-timer-animated/solution.view/menu.js b/1-js/9-object-inheritance/08-class-inheritance/5-menu-timer-animated/solution.view/menu.js similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/5-menu-timer-animated/solution.view/menu.js rename to 1-js/9-object-inheritance/08-class-inheritance/5-menu-timer-animated/solution.view/menu.js diff --git a/1-js/9-object-inheritance/15-class-inheritance/5-menu-timer-animated/source.view/index.html b/1-js/9-object-inheritance/08-class-inheritance/5-menu-timer-animated/source.view/index.html similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/5-menu-timer-animated/source.view/index.html rename to 1-js/9-object-inheritance/08-class-inheritance/5-menu-timer-animated/source.view/index.html diff --git a/1-js/9-object-inheritance/15-class-inheritance/5-menu-timer-animated/source.view/menu.js b/1-js/9-object-inheritance/08-class-inheritance/5-menu-timer-animated/source.view/menu.js similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/5-menu-timer-animated/source.view/menu.js rename to 1-js/9-object-inheritance/08-class-inheritance/5-menu-timer-animated/source.view/menu.js diff --git a/1-js/9-object-inheritance/15-class-inheritance/5-menu-timer-animated/task.md b/1-js/9-object-inheritance/08-class-inheritance/5-menu-timer-animated/task.md similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/5-menu-timer-animated/task.md rename to 1-js/9-object-inheritance/08-class-inheritance/5-menu-timer-animated/task.md diff --git a/1-js/9-object-inheritance/15-class-inheritance/6-constructor-inherited/solution.md b/1-js/9-object-inheritance/08-class-inheritance/6-constructor-inherited/solution.md similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/6-constructor-inherited/solution.md rename to 1-js/9-object-inheritance/08-class-inheritance/6-constructor-inherited/solution.md diff --git a/1-js/9-object-inheritance/15-class-inheritance/6-constructor-inherited/task.md b/1-js/9-object-inheritance/08-class-inheritance/6-constructor-inherited/task.md similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/6-constructor-inherited/task.md rename to 1-js/9-object-inheritance/08-class-inheritance/6-constructor-inherited/task.md diff --git a/1-js/9-object-inheritance/15-class-inheritance/article.md b/1-js/9-object-inheritance/08-class-inheritance/article.md similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/article.md rename to 1-js/9-object-inheritance/08-class-inheritance/article.md diff --git a/1-js/9-object-inheritance/15-class-inheritance/class-inheritance-array-object.png b/1-js/9-object-inheritance/08-class-inheritance/class-inheritance-array-object.png similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/class-inheritance-array-object.png rename to 1-js/9-object-inheritance/08-class-inheritance/class-inheritance-array-object.png diff --git a/1-js/9-object-inheritance/15-class-inheritance/class-inheritance-array-object@2x.png b/1-js/9-object-inheritance/08-class-inheritance/class-inheritance-array-object@2x.png similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/class-inheritance-array-object@2x.png rename to 1-js/9-object-inheritance/08-class-inheritance/class-inheritance-array-object@2x.png diff --git a/1-js/9-object-inheritance/15-class-inheritance/class-inheritance-rabbit-animal.png b/1-js/9-object-inheritance/08-class-inheritance/class-inheritance-rabbit-animal.png similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/class-inheritance-rabbit-animal.png rename to 1-js/9-object-inheritance/08-class-inheritance/class-inheritance-rabbit-animal.png diff --git a/1-js/9-object-inheritance/15-class-inheritance/class-inheritance-rabbit-animal@2x.png b/1-js/9-object-inheritance/08-class-inheritance/class-inheritance-rabbit-animal@2x.png similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/class-inheritance-rabbit-animal@2x.png rename to 1-js/9-object-inheritance/08-class-inheritance/class-inheritance-rabbit-animal@2x.png diff --git a/1-js/9-object-inheritance/15-class-inheritance/class-inheritance-rabbit-run-animal.png b/1-js/9-object-inheritance/08-class-inheritance/class-inheritance-rabbit-run-animal.png similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/class-inheritance-rabbit-run-animal.png rename to 1-js/9-object-inheritance/08-class-inheritance/class-inheritance-rabbit-run-animal.png diff --git a/1-js/9-object-inheritance/15-class-inheritance/class-inheritance-rabbit-run-animal@2x.png b/1-js/9-object-inheritance/08-class-inheritance/class-inheritance-rabbit-run-animal@2x.png similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/class-inheritance-rabbit-run-animal@2x.png rename to 1-js/9-object-inheritance/08-class-inheritance/class-inheritance-rabbit-run-animal@2x.png diff --git a/1-js/9-object-inheritance/15-class-inheritance/console_dir_array.png b/1-js/9-object-inheritance/08-class-inheritance/console_dir_array.png similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/console_dir_array.png rename to 1-js/9-object-inheritance/08-class-inheritance/console_dir_array.png diff --git a/1-js/9-object-inheritance/15-class-inheritance/console_dir_array@2x.png b/1-js/9-object-inheritance/08-class-inheritance/console_dir_array@2x.png similarity index 100% rename from 1-js/9-object-inheritance/15-class-inheritance/console_dir_array@2x.png rename to 1-js/9-object-inheritance/08-class-inheritance/console_dir_array@2x.png diff --git a/1-js/9-object-inheritance/16-instanceof/1-strange-instanceof/solution.md b/1-js/9-object-inheritance/09-instanceof/1-strange-instanceof/solution.md similarity index 100% rename from 1-js/9-object-inheritance/16-instanceof/1-strange-instanceof/solution.md rename to 1-js/9-object-inheritance/09-instanceof/1-strange-instanceof/solution.md diff --git a/1-js/9-object-inheritance/16-instanceof/1-strange-instanceof/task.md b/1-js/9-object-inheritance/09-instanceof/1-strange-instanceof/task.md similarity index 100% rename from 1-js/9-object-inheritance/16-instanceof/1-strange-instanceof/task.md rename to 1-js/9-object-inheritance/09-instanceof/1-strange-instanceof/task.md diff --git a/1-js/9-object-inheritance/16-instanceof/2-instanceof-result/solution.md b/1-js/9-object-inheritance/09-instanceof/2-instanceof-result/solution.md similarity index 100% rename from 1-js/9-object-inheritance/16-instanceof/2-instanceof-result/solution.md rename to 1-js/9-object-inheritance/09-instanceof/2-instanceof-result/solution.md diff --git a/1-js/9-object-inheritance/16-instanceof/2-instanceof-result/task.md b/1-js/9-object-inheritance/09-instanceof/2-instanceof-result/task.md similarity index 100% rename from 1-js/9-object-inheritance/16-instanceof/2-instanceof-result/task.md rename to 1-js/9-object-inheritance/09-instanceof/2-instanceof-result/task.md diff --git a/1-js/9-object-inheritance/16-instanceof/article.md b/1-js/9-object-inheritance/09-instanceof/article.md similarity index 100% rename from 1-js/9-object-inheritance/16-instanceof/article.md rename to 1-js/9-object-inheritance/09-instanceof/article.md diff --git a/1-js/9-object-inheritance/17-oop-errors/1-format-error/solution.md b/1-js/9-object-inheritance/10-oop-errors/1-format-error/solution.md similarity index 100% rename from 1-js/9-object-inheritance/17-oop-errors/1-format-error/solution.md rename to 1-js/9-object-inheritance/10-oop-errors/1-format-error/solution.md diff --git a/1-js/9-object-inheritance/17-oop-errors/1-format-error/task.md b/1-js/9-object-inheritance/10-oop-errors/1-format-error/task.md similarity index 100% rename from 1-js/9-object-inheritance/17-oop-errors/1-format-error/task.md rename to 1-js/9-object-inheritance/10-oop-errors/1-format-error/task.md diff --git a/1-js/9-object-inheritance/17-oop-errors/article.md b/1-js/9-object-inheritance/10-oop-errors/article.md similarity index 100% rename from 1-js/9-object-inheritance/17-oop-errors/article.md rename to 1-js/9-object-inheritance/10-oop-errors/article.md diff --git a/1-js/9-object-inheritance/18-mixins/article.md b/1-js/9-object-inheritance/11-mixins/article.md similarity index 100% rename from 1-js/9-object-inheritance/18-mixins/article.md rename to 1-js/9-object-inheritance/11-mixins/article.md diff --git a/1-js/9-object-inheritance/index.md b/1-js/9-object-inheritance/index.md index f139e118..7053ada8 100644 --- a/1-js/9-object-inheritance/index.md +++ b/1-js/9-object-inheritance/index.md @@ -1,2 +1,3 @@ -# Object inheritance +# Objects, classes, inheritance +In this section we return to objects and learn them even more in-depth. diff --git a/figures.sketch b/figures.sketch index 6bcfe34d..af2202ea 100644 Binary files a/figures.sketch and b/figures.sketch differ