diff --git a/1-js/02-first-steps/12-while-for/article.md b/1-js/02-first-steps/12-while-for/article.md
index 992c21af6..6be50597d 100644
--- a/1-js/02-first-steps/12-while-for/article.md
+++ b/1-js/02-first-steps/12-while-for/article.md
@@ -308,8 +308,7 @@ for (let i = 0; i < 3; i++) {
let input = prompt(`Value at coords (${i},${j})`, '');
- // what if I want to exit from here to Done (below)?
-
+ // what if we want to exit from here to Done (below)?
}
}
diff --git a/1-js/04-object-basics/01-object/article.md b/1-js/04-object-basics/01-object/article.md
index f59ec0292..00706750c 100644
--- a/1-js/04-object-basics/01-object/article.md
+++ b/1-js/04-object-basics/01-object/article.md
@@ -146,6 +146,20 @@ let key = prompt("What do you want to know about the user?", "name");
alert( user[key] ); // John (if enter "name")
```
+<<<<<<< HEAD
+=======
+The dot notation cannot be used in a similar way:
+
+```js run
+let user = {
+ name: "John",
+ age: 30
+};
+
+let key = "name";
+alert( user.key ) // undefined
+```
+>>>>>>> 852ee189170d9022f67ab6d387aeae76810b5923
### Computed properties
diff --git a/1-js/04-object-basics/03-symbol/article.md b/1-js/04-object-basics/03-symbol/article.md
index 8323d6643..55599cccb 100644
--- a/1-js/04-object-basics/03-symbol/article.md
+++ b/1-js/04-object-basics/03-symbol/article.md
@@ -3,11 +3,11 @@
By specification, object property keys may be either of string type, or of symbol type. Not numbers, not booleans, only strings or symbols, these two types.
-Till now we've only seen strings. Now let's see the advantages that symbols can give us.
+Till now we've been using only strings. Now let's see the benefits that symbols can give us.
## Symbols
-"Symbol" value represents a unique identifier.
+A "symbol" represents a unique identifier.
A value of this type can be created using `Symbol()`:
@@ -52,7 +52,7 @@ alert(id); // TypeError: Cannot convert a Symbol value to a string
That's a "language guard" against messing up, because strings and symbols are fundamentally different and should not occasionally convert one into another.
-If we really want to show a symbol, we need to call `.toString()` on it, like here:
+If we really want to show a symbol, we need to explicitly call `.toString()` on it, like here:
```js run
let id = Symbol("id");
*!*
@@ -60,7 +60,7 @@ alert(id.toString()); // Symbol(id), now it works
*/!*
```
-Or get `symbol.description` property to get the description only:
+Or get `symbol.description` property to show the description only:
```js run
let id = Symbol("id");
*!*
@@ -74,13 +74,23 @@ alert(id.description); // id
Symbols allow us to create "hidden" properties of an object, that no other part of code can occasionally access or overwrite.
+<<<<<<< HEAD
For instance, if we want to store an "identifier" for the object `user`, we can use a symbol as a key for it:
+=======
+For instance, if we're working with `user` objects, that belong to a third-party code. We'd like to add identifiers to them.
+
+Let's use a symbol key for it:
+>>>>>>> 852ee189170d9022f67ab6d387aeae76810b5923
```js run
-let user = { name: "John" };
+let user = { // belongs to another code
+ name: "John"
+};
+
let id = Symbol("id");
-user[id] = "ID Value";
+user[id] = 1;
+
alert( user[id] ); // we can access the data using the symbol as the key
```
@@ -106,13 +116,13 @@ Now note that if we used a string `"id"` instead of a symbol for the same purpos
```js run
let user = { name: "John" };
-// our script uses "id" property
-user.id = "ID Value";
+// Our script uses "id" property
+user.id = "Our id value";
-// ...if later another script the uses "id" for its purposes...
+// ...Another script also wants "id" for its purposes...
user.id = "Their id value"
-// boom! overwritten! it did not mean to harm the colleague, but did it!
+// Boom! overwritten by another script!
```
### Symbols in a literal
@@ -127,7 +137,7 @@ let id = Symbol("id");
let user = {
name: "John",
*!*
- [id]: 123 // not just "id: 123"
+ [id]: 123 // not "id: 123"
*/!*
};
```
diff --git a/1-js/05-data-types/03-string/article.md b/1-js/05-data-types/03-string/article.md
index e748d65f0..b7e619188 100644
--- a/1-js/05-data-types/03-string/article.md
+++ b/1-js/05-data-types/03-string/article.md
@@ -355,8 +355,8 @@ alert( "Hello".includes("Bye") ); // false
The optional second argument of `str.includes` is the position to start searching from:
```js run
-alert( "Midget".includes("id") ); // true
-alert( "Midget".includes("id", 3) ); // false, from position 3 there is no "id"
+alert( "Widget".includes("id") ); // true
+alert( "Widget".includes("id", 3) ); // false, from position 3 there is no "id"
```
The methods [str.startsWith](mdn:js/String/startsWith) and [str.endsWith](mdn:js/String/endsWith) do exactly what they say:
diff --git a/1-js/05-data-types/05-array-methods/9-shuffle/solution.md b/1-js/05-data-types/05-array-methods/9-shuffle/solution.md
index a43715db8..31f7a2948 100644
--- a/1-js/05-data-types/05-array-methods/9-shuffle/solution.md
+++ b/1-js/05-data-types/05-array-methods/9-shuffle/solution.md
@@ -68,7 +68,13 @@ There are other good ways to do the task. For instance, there's a great algorith
function shuffle(array) {
for (let i = array.length - 1; i > 0; i--) {
let j = Math.floor(Math.random() * (i + 1)); // random index from 0 to i
- [array[i], array[j]] = [array[j], array[i]]; // swap elements
+
+ // swap elements array[i] and array[j]
+ // we use "destructuring assignment" syntax to achieve that
+ // you'll find more details about that syntax in later chapters
+ // same can be written as:
+ // let t = array[i]; array[i] = array[j]; array[j] = t
+ [array[i], array[j]] = [array[j], array[i]];
}
}
```
diff --git a/1-js/09-classes/07-mixins/article.md b/1-js/09-classes/07-mixins/article.md
index 7b6d9ebad..2502c3982 100644
--- a/1-js/09-classes/07-mixins/article.md
+++ b/1-js/09-classes/07-mixins/article.md
@@ -2,13 +2,17 @@
In JavaScript we can only inherit from a single object. There can be only one `[[Prototype]]` for an object. And a class may extend only one other class.
+<<<<<<< HEAD
But sometimes that feels limiting. For instance, I have a class `StreetSweeper` and a class `Bicycle`, and want to make a `StreetSweepingBicycle`.
+=======
+But sometimes that feels limiting. For instance, we have a class `StreetSweeper` and a class `Bicycle`, and want to make their mix: a `StreetSweepingBicycle`.
+>>>>>>> 852ee189170d9022f67ab6d387aeae76810b5923
Or, talking about programming, we have a class `Renderer` that implements templating and a class `EventEmitter` that implements event handling, and want to merge these functionalities together with a class `Page`, to make a page that can use templates and emit events.
There's a concept that can help here, called "mixins".
-As defined in Wikipedia, a [mixin](https://en.wikipedia.org/wiki/Mixin) is a class that contains methods for use by other classes without having to be the parent class of those other classes.
+As defined in Wikipedia, a [mixin](https://en.wikipedia.org/wiki/Mixin) is a class containing methods that can be used by other classes without a need to inherit from it.
In other words, a *mixin* provides methods that implement a certain behavior, but we do not use it alone, we use it to add the behavior to other classes.
diff --git a/1-js/10-error-handling/1-try-catch/article.md b/1-js/10-error-handling/1-try-catch/article.md
index 3f2e419bf..82941387a 100644
--- a/1-js/10-error-handling/1-try-catch/article.md
+++ b/1-js/10-error-handling/1-try-catch/article.md
@@ -302,7 +302,7 @@ try {
*!*
alert(e.name); // SyntaxError
*/!*
- alert(e.message); // Unexpected token o in JSON at position 0
+ alert(e.message); // Unexpected token o in JSON at position 2
}
```
diff --git a/1-js/11-async/01-callbacks/article.md b/1-js/11-async/01-callbacks/article.md
index a9183c80f..742b621b7 100644
--- a/1-js/11-async/01-callbacks/article.md
+++ b/1-js/11-async/01-callbacks/article.md
@@ -222,6 +222,30 @@ As calls become more nested, the code becomes deeper and increasingly more diffi
That's sometimes called "callback hell" or "pyramid of doom."
+
+

The "pyramid" of nested calls grows to the right with every asynchronous action. Soon it spirals out of control.
diff --git a/1-js/11-async/01-callbacks/callback-hell.svg b/1-js/11-async/01-callbacks/callback-hell.svg
index 574d7dfbf..b13d3cd7a 100644
--- a/1-js/11-async/01-callbacks/callback-hell.svg
+++ b/1-js/11-async/01-callbacks/callback-hell.svg
@@ -1,3 +1,4 @@
+<<<<<<< HEAD
\ No newline at end of file
+
+=======
+
+>>>>>>> 852ee189170d9022f67ab6d387aeae76810b5923
diff --git a/1-js/11-async/04-promise-error-handling/article.md b/1-js/11-async/04-promise-error-handling/article.md
index ca67202aa..7819a38c7 100644
--- a/1-js/11-async/04-promise-error-handling/article.md
+++ b/1-js/11-async/04-promise-error-handling/article.md
@@ -150,7 +150,11 @@ new Promise((resolve, reject) => {
}
}).then(function() {
+<<<<<<< HEAD
/* never runs here */
+=======
+ /* doesn't run here */
+>>>>>>> 852ee189170d9022f67ab6d387aeae76810b5923
}).catch(error => { // (**)
alert(`The unknown error has occurred: ${error}`);
@@ -266,7 +270,11 @@ new Promise(function() {
In case of an error, the promise state becomes "rejected", and the execution should jump to the closest rejection handler. But there is no such handler in the examples above. So the error gets "stuck".
+<<<<<<< HEAD
In practice, just like with a regular unhandled errors, it means that something has terribly gone wrong, the script probably died.
+=======
+In practice, just like with regular unhandled errors in code, it means that something has terribly gone wrong.
+>>>>>>> 852ee189170d9022f67ab6d387aeae76810b5923
Most JavaScript engines track such situations and generate a global error in that case. We can see it in the console.
diff --git a/1-js/12-generators-iterators/1-generators/article.md b/1-js/12-generators-iterators/1-generators/article.md
index f6fcfb00d..82e54edf9 100644
--- a/1-js/12-generators-iterators/1-generators/article.md
+++ b/1-js/12-generators-iterators/1-generators/article.md
@@ -243,10 +243,25 @@ That surely would require a `break` in `for..of`, otherwise the loop would repea
Generator composition is a special feature of generators that allows to transparently "embed" generators in each other.
+<<<<<<< HEAD
For instance, we'd like to generate a sequence of:
- digits `0..9` (character codes 48..57),
- followed by alphabet letters `a..z` (character codes 65..90)
- followed by uppercased letters `A..Z` (character codes 97..122)
+=======
+For instance, we have a function that generates a sequence of numbers:
+
+```js
+function* generateSequence(start, end) {
+ for (let i = start; i <= end; i++) yield i;
+}
+```
+
+Now we'd like to reuse it for generation of a more complex sequence:
+- first, digits `0..9` (with character codes 48..57),
+- followed by alphabet letters `A..Z` (character codes 65..90)
+- followed by uppercased letters `a..z` (character codes 97..122)
+>>>>>>> 852ee189170d9022f67ab6d387aeae76810b5923
Then we plan to create passwords by selecting characters from it (could add syntax characters as well), but need to generate the sequence first.
diff --git a/1-js/12-generators-iterators/2-async-iterators-generators/article.md b/1-js/12-generators-iterators/2-async-iterators-generators/article.md
index 45cf73938..5ff9b6493 100644
--- a/1-js/12-generators-iterators/2-async-iterators-generators/article.md
+++ b/1-js/12-generators-iterators/2-async-iterators-generators/article.md
@@ -280,7 +280,11 @@ for await (let commit of fetchCommits(repo)) {
}
```
+<<<<<<< HEAD
We'd like `fetchCommits` to get commits for us, making requests whenever needed. And let it care about all pagination stuff, for us it'll be a simple `for await..of`.
+=======
+We'd like to make a function `fetchCommits(repo)` that gets commits for us, making requests whenever needed. And let it care about all pagination stuff, for us it'll be a simple `for await..of`.
+>>>>>>> 852ee189170d9022f67ab6d387aeae76810b5923
With async generators that's pretty easy to implement:
@@ -358,4 +362,8 @@ In web-development we often meet streams of data, when it flows chunk-by-chunk.
We could use async generators to process such data, but there's also another API called Streams, that may be more convenient, as it provides special interfaces to transform the data and to pass it from one stream to another (e.g. download from one place and immediately send elsewhere). But they are also more complex.
+<<<<<<< HEAD
Streams API not a part of JavaScript language standard. Streams and async generators complement each other, both are great ways to handle async data flows.
+=======
+Streams API is not a part of JavaScript language standard.
+>>>>>>> 852ee189170d9022f67ab6d387aeae76810b5923
diff --git a/1-js/99-js-misc/01-proxy/03-observable/task.md b/1-js/99-js-misc/01-proxy/03-observable/task.md
new file mode 100644
index 000000000..754d9f3bd
--- /dev/null
+++ b/1-js/99-js-misc/01-proxy/03-observable/task.md
@@ -0,0 +1,27 @@
+
+# Observable
+
+Create a function `makeObservable(target)` that "makes the object observable" by returning a proxy.
+
+Here's how it should work:
+
+```js run
+function makeObservable(target) {
+ /* your code */
+}
+
+let user = {};
+user = makeObservable(user);
+
+user.observe((key, value) => {
+ alert(`SET ${key}=${value}`);
+});
+
+user.name = "John"; // alerts: SET name=John
+```
+
+In other words, an object returned by `makeObservable` is just like the original one, but also has the method `observe(handler)` that sets `handler` function to be called on any property change.
+
+Whenever a property changes, `handler(key, value)` is called with the name and value of the property.
+
+P.S. In this task, please only take care about writing to a property. Other operations can be implemented in a similar way.
diff --git a/1-js/99-js-misc/01-proxy/article.md b/1-js/99-js-misc/01-proxy/article.md
new file mode 100644
index 000000000..7a00ef663
--- /dev/null
+++ b/1-js/99-js-misc/01-proxy/article.md
@@ -0,0 +1,1030 @@
+# Proxy and Reflect
+
+A `Proxy` object wraps another object and intercepts operations, like reading/writing properties and others, optionally handling them on its own, or transparently allowing the object to handle them.
+
+Proxies are used in many libraries and some browser frameworks. We'll see many practical applications in this chapter.
+
+The syntax:
+
+```js
+let proxy = new Proxy(target, handler)
+```
+
+- `target` -- is an object to wrap, can be anything, including functions.
+- `handler` -- proxy configuration: an object with "traps": methods that intercept operations., e.g. `get` trap is for reading a property of `target`, `set` trap - for writing a property into `target`, etc.
+
+For operations on `proxy`, if there's a corresponding trap in `handler`, then it runs, and the proxy has a chance to handle it, otherwise the operation is performed on `target`.
+
+As a starting example, let's create a proxy without any traps:
+
+```js run
+let target = {};
+let proxy = new Proxy(target, {}); // empty handler
+
+proxy.test = 5; // writing to proxy (1)
+alert(target.test); // 5, the property appeared in target!
+
+alert(proxy.test); // 5, we can read it from proxy too (2)
+
+for(let key in proxy) alert(key); // test, iteration works (3)
+```
+
+As there are no traps, all operations on `proxy` are forwarded to `target`.
+
+1. A writing operation `proxy.test=` sets the value on `target`.
+2. A reading operation `proxy.test` returns the value from `target`.
+3. Iteration over `proxy` returns values from `target`.
+
+As we can see, without any traps, `proxy` is a transparent wrapper around `target`.
+
+
+
+`Proxy` is a special "exotic object". It doesn't have own properties. With an empty `handler` it transparently forwards operations to `target`.
+
+To activate more capabilities, let's add traps.
+
+What can we intercept by them?
+
+For most operations on objects, there's a so-called "internal method" in JavaScript specificaiton, that describes on the lowest level, how it works. For instance, `[[Get]]` - the internal method to read a property, `[[Set]]` -- the internal method to write a property, and so on. These methods are only used in the specification, we can't them directly by name.
+
+Proxy traps inercept invocations of these methods. They are listed in [Proxy specification](https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots) and in the table below.
+
+For every internal method, there's a trap in this table: the name of the method that we can add to `handler` parameter of `new Proxy` to intercept the operation:
+
+| Internal Method | Handler Method | Triggers when... |
+|-----------------|----------------|-------------|
+| `[[Get]]` | `get` | reading a property |
+| `[[Set]]` | `set` | writing to a property |
+| `[[HasProperty]]` | `has` | `in` operator |
+| `[[Delete]]` | `deleteProperty` | `delete` operator |
+| `[[Call]]` | `apply` | function call |
+| `[[Construct]]` | `construct` | `new` operator |
+| `[[GetPrototypeOf]]` | `getPrototypeOf` | [Object.getPrototypeOf](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getPrototypeOf) |
+| `[[SetPrototypeOf]]` | `setPrototypeOf` | [Object.setPrototypeOf](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf) |
+| `[[IsExtensible]]` | `isExtensible` | [Object.isExtensible](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isExtensible) |
+| `[[PreventExtensions]]` | `preventExtensions` | [Object.preventExtensions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/preventExtensions) |
+| `[[DefineOwnProperty]]` | `defineProperty` | [Object.defineProperty](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty), [Object.defineProperties](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties) |
+| `[[GetOwnProperty]]` | `getOwnPropertyDescriptor` | [Object.getOwnPropertyDescriptor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptor), `for..in`, `Object.keys/values/entries` |
+| `[[OwnPropertyKeys]]` | `ownKeys` | [Object.getOwnPropertyNames](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames), [Object.getOwnPropertySymbols](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertySymbols), `for..in`, `Object/keys/values/entries` |
+
+```warn header="Invariants"
+JavaScript enforces some invariants -- conditions that must be fulfilled by internal methods and traps.
+
+Most of them are for return values:
+- `[[Set]]` must return `true` if the value was written successfully, otherwise `false`.
+- `[[Delete]]` must return `true` if the value was deleted successfully, otherwise `false`.
+- ...and so on, we'll see more in examples below.
+
+There are some other invariants, like:
+- `[[GetPrototypeOf]]`, applied to the proxy object must return the same value as `[[GetPrototypeOf]]` applied to the proxy object's target object. In other words, reading prototype of a proxy must always return the prototype of the target object.
+
+Traps can intercept these operations, but they must follow these rules.
+
+Invariants ensure correct and consistent behavior of language features. The full invariants list is in [the specification](https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots), you probably won't violate them, if not doing something weird.
+```
+
+Let's see how that works on practical examples.
+
+## Default value with "get" trap
+
+The most common traps are for reading/writing properties.
+
+To intercept the reading, the `handler` should have a method `get(target, property, receiver)`.
+
+It triggers when a property is read, with following arguments:
+
+- `target` -- is the target object, the one passed as the first argument to `new Proxy`,
+- `property` -- property name,
+- `receiver` -- if the target property is a getter, then `receiver` is the object that's going to be used as `this` in its call. Usually that's the `proxy` object itself (or an object that inherits from it, if we inherit from proxy). Right now we don't need this argument, will be explained in more details letter.
+
+Let's use `get` to implement default values for an object.
+
+We'll make a numeric array that returns return `0` for non-existant values.
+
+Usually when one tries to get a non-existing array item, they get `undefined`, but we'll wrap a regular array into proxy that traps reading and returns `0` if there's no such property:
+
+```js run
+let numbers = [0, 1, 2];
+
+numbers = new Proxy(numbers, {
+ get(target, prop) {
+ if (prop in target) {
+ return target[prop];
+ } else {
+ return 0; // default value
+ }
+ }
+});
+
+*!*
+alert( numbers[1] ); // 1
+alert( numbers[123] ); // 0 (no such item)
+*/!*
+```
+
+As we can see, it's quite easy to do with `get` trap.
+
+We can use `Proxy` to implement any logic for "default" values.
+
+Imagine, we have a dictionary with phrases along with translations:
+
+```js run
+let dictionary = {
+ 'Hello': 'Hola',
+ 'Bye': 'Adiós'
+};
+
+alert( dictionary['Hello'] ); // Hola
+alert( dictionary['Welcome'] ); // undefined
+```
+
+Right now, if there's no phrase, reading from `dictionary` returns `undefined`. But in practice, leaving a phrase non-translated is usually better than `undefined`. So let's make it return a non-translated phrase in that case instead of `undefined`.
+
+To achieve that, we'll wrap `dictionary` in a proxy that intercepts reading operations:
+
+```js run
+let dictionary = {
+ 'Hello': 'Hola',
+ 'Bye': 'Adiós'
+};
+
+dictionary = new Proxy(dictionary, {
+*!*
+ get(target, phrase) { // intercept reading a property from dictionary
+*/!*
+ if (phrase in target) { // if we have it in the dictionary
+ return target[phrase]; // return the translation
+ } else {
+ // otherwise, return the non-translated phrase
+ return phrase;
+ }
+ }
+});
+
+// Look up arbitrary phrases in the dictionary!
+// At worst, they are not translated.
+alert( dictionary['Hello'] ); // Hola
+*!*
+alert( dictionary['Welcome to Proxy']); // Welcome to Proxy (no translation)
+*/!*
+```
+
+````smart
+Please note how the proxy overwrites the variable:
+
+```js
+dictionary = new Proxy(dictionary, ...);
+```
+
+The proxy should totally replace the target object everywhere. No one should ever reference the target object after it got proxied. Otherwise it's easy to mess up.
+````
+
+## Validation with "set" trap
+
+Let's say we want an array exclusively for numbers. If a value of another type is added, there should be an error.
+
+The `set` trap triggers when a property is written.
+
+`set(target, property, value, receiver)`:
+
+- `target` -- is the target object, the one passed as the first argument to `new Proxy`,
+- `property` -- property name,
+- `value` -- property value,
+- `receiver` -- similar to `get` trap, matters only for setter properties.
+
+The `set` trap should return `true` if setting is successful, and `false` otherwise (triggers `TypeError`).
+
+Let's use it to validate new values:
+
+```js run
+let numbers = [];
+
+numbers = new Proxy(numbers, { // (*)
+*!*
+ set(target, prop, val) { // to intercept property writing
+*/!*
+ if (typeof val == 'number') {
+ target[prop] = val;
+ return true;
+ } else {
+ return false;
+ }
+ }
+});
+
+numbers.push(1); // added successfully
+numbers.push(2); // added successfully
+alert("Length is: " + numbers.length); // 2
+
+*!*
+numbers.push("test"); // TypeError ('set' on proxy returned false)
+*/!*
+
+alert("This line is never reached (error in the line above)");
+```
+
+Please note: the built-in functionality of arrays is still working! Values are added by `push`. The `length` property auto-increases when values are added. Our proxy doesn't break anything.
+
+We don't have to override value-adding array methods like `push` and `unshift`, and so on, to add checks in there, because internally they use `[[Set]]` operation, that's intercepted by the proxy.
+
+So the code is clean and concise.
+
+```warn header="Don't forget to return `true`"
+As said above, there are invariants to be held.
+
+For `set`, it must return `true` for a successful write.
+
+If we forget to do it or return any falsy value, the operation triggers `TypeError`.
+```
+
+## Iteration with "ownKeys" and "getOwnPropertyDescriptor"
+
+`Object.keys`, `for..in` loop and most other methods that iterate over object properties use `[[OwnPropertyKeys]]` internal method (intercepted by `ownKeys` trap) to get a list of properties.
+
+Such methods differ in details:
+- `Object.getOwnPropertyNames(obj)` returns non-symbol keys.
+- `Object.getOwnPropertySymbols(obj)` returns symbol keys.
+- `Object.keys/values()` returns non-symbol keys/values with `enumerable` flag (property flags were explained in the chapter ).
+- `for..in` loops over non-symbol keys with `enumerable` flag, and also prototype keys.
+
+...But all of them start with that list.
+
+In the example below we use `ownKeys` trap to make `for..in` loop over `user`, and also `Object.keys` and `Object.values`, to skip properties starting with an underscore `_`:
+
+```js run
+let user = {
+ name: "John",
+ age: 30,
+ _password: "***"
+};
+
+user = new Proxy(user, {
+*!*
+ ownKeys(target) {
+*/!*
+ return Object.keys(target).filter(key => !key.startsWith('_'));
+ }
+});
+
+// "ownKeys" filters out _password
+for(let key in user) alert(key); // name, then: age
+
+// same effect on these methods:
+alert( Object.keys(user) ); // name,age
+alert( Object.values(user) ); // John,30
+```
+
+So far, it works.
+
+Although, if we return a key that doesn't exist in the object, `Object.keys` won't list it:
+
+```js run
+let user = { };
+
+user = new Proxy(user, {
+*!*
+ ownKeys(target) {
+*/!*
+ return ['a', 'b', 'c'];
+ }
+});
+
+alert( Object.keys(user) ); //
+```
+
+Why? The reason is simple: `Object.keys` returns only properties with `enumerable` flag. To check for it, it calls the internal method `[[GetOwnProperty]]` for every property to get [its descriptor](info:property-descriptors). And here, as there's no property, its descriptor is empty, no `enumerable` flag, so it's skipped.
+
+For `Object.keys` to return a property, we need it either exist in the object, with `enumerable` flag, or we can intercept calls to `[[GetOwnProperty]]` (the trap `getOwnPropertyDescriptor` does it), and return a descriptor with `enumerable: true`.
+
+Here's a working code:
+
+```js run
+let user = { };
+
+user = new Proxy(user, {
+ ownKeys(target) { // called once to get a list of properties
+ return ['a', 'b', 'c'];
+ },
+
+ getOwnPropertyDescriptor(target, prop) { // called for every property
+ return {
+ enumerable: true,
+ configurable: true
+ /* ...other flags, probable "value:..."" */
+ };
+ }
+
+});
+
+alert( Object.keys(user) ); // a, b, c
+```
+
+Let's note once again: we only need to intercept `[[GetOwnProperty]]` if the property is absent in the object.
+
+## Protected properties with "deleteProperty" and other traps
+
+There's a widespread convention that properties and methods prefixed by an underscore `_` are internal. They shouldn't be accessed from outside the object.
+
+Technically, that's possible though:
+
+```js run
+let user = {
+ name: "John",
+ _password: "secret"
+};
+
+alert(user._password); // secret
+```
+
+Let's use proxies to prevent any access to properties starting with `_`.
+
+We'll need the traps:
+- `get` to throw an error when reading such property,
+- `set` to throw an error when writing,
+- `deleteProperty` to throw an error when deleting,
+- `ownKeys` to exclude properties starting with `_` from `for..in` and methods like `Object.keys`.
+
+Here's the code:
+
+```js run
+let user = {
+ name: "John",
+ _password: "***"
+};
+
+user = new Proxy(user, {
+*!*
+ get(target, prop) {
+*/!*
+ if (prop.startsWith('_')) {
+ throw new Error("Access denied");
+ }
+ let value = target[prop];
+ return (typeof value === 'function') ? value.bind(target) : value; // (*)
+ },
+*!*
+ set(target, prop, val) { // to intercept property writing
+*/!*
+ if (prop.startsWith('_')) {
+ throw new Error("Access denied");
+ } else {
+ target[prop] = val;
+ return true;
+ }
+ },
+*!*
+ deleteProperty(target, prop) { // to intercept property deletion
+*/!*
+ if (prop.startsWith('_')) {
+ throw new Error("Access denied");
+ } else {
+ delete target[prop];
+ return true;
+ }
+ },
+*!*
+ ownKeys(target) { // to intercept property list
+*/!*
+ return Object.keys(target).filter(key => !key.startsWith('_'));
+ }
+});
+
+// "get" doesn't allow to read _password
+try {
+ alert(user._password); // Error: Access denied
+} catch(e) { alert(e.message); }
+
+// "set" doesn't allow to write _password
+try {
+ user._password = "test"; // Error: Access denied
+} catch(e) { alert(e.message); }
+
+// "deleteProperty" doesn't allow to delete _password
+try {
+ delete user._password; // Error: Access denied
+} catch(e) { alert(e.message); }
+
+// "ownKeys" filters out _password
+for(let key in user) alert(key); // name
+```
+
+Please note the important detail in `get` trap, in the line `(*)`:
+
+```js
+get(target, prop) {
+ // ...
+ let value = target[prop];
+*!*
+ return (typeof value === 'function') ? value.bind(target) : value; // (*)
+*/!*
+}
+```
+
+Why do we need for a function to call `value.bind(target)`?
+
+The reason is that object methods, such as `user.checkPassword()`, must be able to access `_password`:
+
+```js
+user = {
+ // ...
+ checkPassword(value) {
+ // object method must be able to read _password
+ return value === this._password;
+ }
+}
+```
+
+
+A call to `user.checkPassword()` call gets proxied `user` as `this` (the object before dot becomes `this`), so when it tries to access `this._password`, the `get` trap activates (it triggers on any property read) and throws an error.
+
+So we bind the context of object methods to the original object, `target`, in the line `(*)`. Then their future calls will use `target` as `this`, without any traps.
+
+That solution usually works, but isn't ideal, as a method may pass the unproxied object somewhere else, and then we'll get messed up: where's the original object, and where's the proxied one.
+
+Besides, an object may be proxied multiple times (multiple proxies may add different "tweaks" to the object), and if we pass an unwrapped object to a method, there may be unexpected consequences.
+
+So, such proxy shouldn't be used everywhere.
+
+```smart header="Private properties of a class"
+Modern JavaScript engines natively support private properties in classes, prefixed with `#`. They are described in the chapter . No proxies required.
+
+Such properties have their own issues though. In particular, they are not inherited.
+```
+
+## "In range" with "has" trap
+
+Let's see more examples.
+
+We have a range object:
+
+```js
+let range = {
+ start: 1,
+ end: 10
+};
+```
+
+We'd like to use `in` operator to check that a number is in `range`.
+
+The `has` trap intercepts `in` calls.
+
+`has(target, property)`
+
+- `target` -- is the target object, passed as the first argument to `new Proxy`,
+- `property` -- property name
+
+Here's the demo:
+
+```js run
+let range = {
+ start: 1,
+ end: 10
+};
+
+range = new Proxy(range, {
+*!*
+ has(target, prop) {
+*/!*
+ return prop >= target.start && prop <= target.end
+ }
+});
+
+*!*
+alert(5 in range); // true
+alert(50 in range); // false
+*/!*
+```
+
+A nice syntactic sugar, isn't it? And very simple to implement.
+
+## Wrapping functions: "apply"
+
+We can wrap a proxy around a function as well.
+
+The `apply(target, thisArg, args)` trap handles calling a proxy as function:
+
+- `target` is the target object (function is an object in JavaScript),
+- `thisArg` is the value of `this`.
+- `args` is a list of arguments.
+
+For example, let's recall `delay(f, ms)` decorator, that we did in the chapter .
+
+In that chapter we did it without proxies. A call to `delay(f, ms)` returned a function that forwards all calls to `f` after `ms` milliseconds.
+
+Here's the previous, function-based implementation:
+
+```js run
+function delay(f, ms) {
+ // return a wrapper that passes the call to f after the timeout
+ return function() { // (*)
+ setTimeout(() => f.apply(this, arguments), ms);
+ };
+}
+
+function sayHi(user) {
+ alert(`Hello, ${user}!`);
+}
+
+// after this wrapping, calls to sayHi will be delayed for 3 seconds
+sayHi = delay(sayHi, 3000);
+
+sayHi("John"); // Hello, John! (after 3 seconds)
+```
+
+As we've seen already, that mostly works. The wrapper function `(*)` performs the call after the timeout.
+
+But a wrapper function does not forward property read/write operations or anything else. After the wrapping, the access is lost to properties of the original functions, such as `name`, `length` and others:
+
+```js run
+function delay(f, ms) {
+ return function() {
+ setTimeout(() => f.apply(this, arguments), ms);
+ };
+}
+
+function sayHi(user) {
+ alert(`Hello, ${user}!`);
+}
+
+*!*
+alert(sayHi.length); // 1 (function length is the arguments count in its declaration)
+*/!*
+
+sayHi = delay(sayHi, 3000);
+
+*!*
+alert(sayHi.length); // 0 (in the wrapper declaration, there are zero arguments)
+*/!*
+```
+
+`Proxy` is much more powerful, as it forwards everything to the target object.
+
+Let's use `Proxy` instead of a wrapping function:
+
+```js run
+function delay(f, ms) {
+ return new Proxy(f, {
+ apply(target, thisArg, args) {
+ setTimeout(() => target.apply(thisArg, args), ms);
+ }
+ });
+}
+
+function sayHi(user) {
+ alert(`Hello, ${user}!`);
+}
+
+sayHi = delay(sayHi, 3000);
+
+*!*
+alert(sayHi.length); // 1 (*) proxy forwards "get length" operation to the target
+*/!*
+
+sayHi("John"); // Hello, John! (after 3 seconds)
+```
+
+The result is the same, but now not only calls, but all operations on the proxy are forwarded to the original function. So `sayHi.length` is returned correctly after the wrapping in the line `(*)`.
+
+We've got a "richer" wrapper.
+
+There exist other traps: the full list is in the beginning of this chapter. Their usage pattern is similar to the above.
+
+## Reflect
+
+`Reflect` is a built-in object that simplifies creation of `Proxy`.
+
+It was said previously that internal methods, such as `[[Get]]`, `[[Set]]` and others are specifiction only, they can't be called directly.
+
+`Reflect` object makes that somewhat possible. Its methods are minimal wrappers around the internal methods.
+
+Here are examples of operations and `Reflect` calls that do the same:
+
+| Operation | `Reflect` call | Internal method |
+|-----------------|----------------|-------------|
+| `obj[prop]` | `Reflect.get(obj, prop)` | `[[Get]]` |
+| `obj[prop] = value` | `Reflect.set(obj, prop, value)` | `[[Set]]` |
+| `delete obj[prop]` | `Reflect.deleteProperty(obj, prop)` | `[[HasProperty]]` |
+| `new F(value)` | `Reflect.construct(F, value)` | `[[Construct]]` |
+| ... | ... | ... |
+
+For example:
+
+```js run
+let user = {};
+
+Reflect.set(user, 'name', 'John');
+
+alert(user.name); // John
+```
+
+In particular, `Reflect` allows to call operators (`new`, `delete`...) as functions (`Reflect.construct`, `Reflect.deleteProperty`, ...). That's an interesting capability, but here another thing is important.
+
+**For every internal method, trappable by `Proxy`, there's a corresponding method in `Reflect`, with the same name and arguments as `Proxy` trap.**
+
+So we can use `Reflect` to forward an operation to the original object.
+
+In this example both traps `get` and `set` transparently (as if they didn't exist) forward reading/writing operations to the object, showing a message:
+
+```js run
+let user = {
+ name: "John",
+};
+
+user = new Proxy(user, {
+ get(target, prop, receiver) {
+ alert(`GET ${prop}`);
+*!*
+ return Reflect.get(target, prop, receiver); // (1)
+*/!*
+ },
+ set(target, prop, val, receiver) {
+ alert(`SET ${prop}=${val}`);
+*!*
+ return Reflect.set(target, prop, val, receiver); // (2)
+*/!*
+ }
+});
+
+let name = user.name; // shows "GET name"
+user.name = "Pete"; // shows "SET name=Pete"
+```
+
+Here:
+
+- `Reflect.get` reads an object property.
+- `Reflect.set` writes an object property and returns `true` if successful, `false` otherwise.
+
+That is, everything's simple: if a trap wants to forward the call to the object, it's enough to call `Reflect.` with the same arguments.
+
+In most cases we can do the same without `Reflect`, for instance, reading a property `Reflect.get(target, prop, receiver)` can be replaced by `target[prop]`. There are important nuances though.
+
+### Proxying a getter
+
+Let's see an example that demonstrates why `Reflect.get` is better. And we'll also see why `get/set` have the fourth argument `receiver`, that we didn't use before.
+
+We have an object `user` with `_name` property and a getter for it.
+
+Here's a proxy around it:
+
+```js run
+let user = {
+ _name: "Guest",
+ get name() {
+ return this._name;
+ }
+};
+
+*!*
+let userProxy = new Proxy(user, {
+ get(target, prop, receiver) {
+ return target[prop];
+ }
+});
+*/!*
+
+alert(userProxy.name); // Guest
+```
+
+The `get` trap is "transparent" here, it returns the original property, and doesn't do anything else. That's enough for our example.
+
+Everything seems to be all right. But let's make the example a little bit more complex.
+
+After inheriting another object `admin` from `user`, we can observe the incorrect behavior:
+
+```js run
+let user = {
+ _name: "Guest",
+ get name() {
+ return this._name;
+ }
+};
+
+let userProxy = new Proxy(user, {
+ get(target, prop, receiver) {
+ return target[prop]; // (*) target = user
+ }
+});
+
+*!*
+let admin = {
+ __proto__: userProxy,
+ _name: "Admin"
+};
+
+// Expected: Admin
+alert(admin.name); // outputs: Guest (?!?)
+*/!*
+```
+
+Reading `admin.name` should return `"Admin"`, not `"Guest"`!
+
+What's the matter? Maybe we did something wrong with the inheritance?
+
+But if we remove the proxy, then everything will work as expected.
+
+The problem is actually in the proxy, in the line `(*)`.
+
+1. When we read `admin.name`, as `admin` object doesn't have such own property, the search goes to its prototype.
+2. The prototype is `userProxy`.
+3. When reading `name` property from the proxy, its `get` trap triggers and returns it from the original object as `target[prop]` in the line `(*)`.
+
+ A call to `target[prop]`, when `prop` is a getter, runs its code in the context `this=target`. So the result is `this._name` from the original object `target`, that is: from `user`.
+
+To fix such situations, we need `receiver`, the third argument of `get` trap. It keeps the correct `this` to be passed to a getter. In our case that's `admin`.
+
+How to pass the context for a getter? For a regular function we could use `call/apply`, but that's a getter, it's not "called", just accessed.
+
+`Reflect.get` can do that. Everything will work right if we use it.
+
+Here's the corrected variant:
+
+```js run
+let user = {
+ _name: "Guest",
+ get name() {
+ return this._name;
+ }
+};
+
+let userProxy = new Proxy(user, {
+ get(target, prop, receiver) { // receiver = admin
+*!*
+ return Reflect.get(target, prop, receiver); // (*)
+*/!*
+ }
+});
+
+
+let admin = {
+ __proto__: userProxy,
+ _name: "Admin"
+};
+
+*!*
+alert(admin.name); // Admin
+*/!*
+```
+
+Now `receiver` that keeps a reference to the correct `this` (that is `admin`), is passed to the getter using `Reflect.get` in the line `(*)`.
+
+We can rewrite the trap even shorter:
+
+```js
+get(target, prop, receiver) {
+ return Reflect.get(*!*...arguments*/!*);
+}
+```
+
+
+`Reflect` calls are named exactly the same way as traps and accept the same arguments. They were specifically designed this way.
+
+So, `return Reflect...` provides a safe no-brainer to forward the operation and make sure we don't forget anything related to that.
+
+## Proxy limitations
+
+Proxies provide a unique way to alter or tweak the behavior of the existing objects at the lowest level. Still, it's not perfect. There are limitations.
+
+### Built-in objects: Internal slots
+
+Many built-in objects, for example `Map`, `Set`, `Date`, `Promise` and others make use of so-called "internal slots".
+
+These are like properties, but reserved for internal, specification-only purposes. For instance, `Map` stores items in the internal slot `[[MapData]]`. Built-in methods access them directly, not via `[[Get]]/[[Set]]` internal methods. So `Proxy` can't intercept that.
+
+Why care? They are internal anyway!
+
+Well, here's the issue. After such built-in object gets proxied, the proxy doesn't have these internal slots, so built-in methods will fail.
+
+For example:
+
+```js run
+let map = new Map();
+
+let proxy = new Proxy(map, {});
+
+*!*
+proxy.set('test', 1); // Error
+*/!*
+```
+
+Internally, a `Map` stores all data in its `[[MapData]]` internal slot. The proxy doesn't have such slot. The [built-in method `Map.prototype.set`](https://tc39.es/ecma262/#sec-map.prototype.set) method tries to access the internal property `this.[[MapData]]`, but because `this=proxy`, can't find it in `proxy` and just fails.
+
+Fortunately, there's a way to fix it:
+
+```js run
+let map = new Map();
+
+let proxy = new Proxy(map, {
+ get(target, prop, receiver) {
+ let value = Reflect.get(...arguments);
+*!*
+ return typeof value == 'function' ? value.bind(target) : value;
+*/!*
+ }
+});
+
+proxy.set('test', 1);
+alert(proxy.get('test')); // 1 (works!)
+```
+
+Now it works fine, because `get` trap binds function properties, such as `map.set`, to the target object (`map`) itself.
+
+Unlike the previous example, the value of `this` inside `proxy.set(...)` will be not `proxy`, but the original `map`. So when the internal implementation of `set` tries to access `this.[[MapData]]` internal slot, it succeeds.
+
+```smart header="`Array` has no internal slots"
+A notable exception: built-in `Array` doesn't use internal slots. That's for historical reasons, as it appeared so long ago.
+
+So there's no such problem when proxying an array.
+```
+
+### Private fields
+
+The similar thing happens with private class fields.
+
+For example, `getName()` method accesses the private `#name` property and breaks after proxying:
+
+```js run
+class User {
+ #name = "Guest";
+
+ getName() {
+ return this.#name;
+ }
+}
+
+let user = new User();
+
+user = new Proxy(user, {});
+
+*!*
+alert(user.getName()); // Error
+*/!*
+```
+
+The reason is that private fields are implemented using internal slots. JavaScript does not use `[[Get]]/[[Set]]` when accessing them.
+
+In the call `getName()` the value of `this` is the proxied `user`, and it doesn't have the slot with private fields.
+
+Once again, the solution with binding the method makes it work:
+
+```js run
+class User {
+ #name = "Guest";
+
+ getName() {
+ return this.#name;
+ }
+}
+
+let user = new User();
+
+user = new Proxy(user, {
+ get(target, prop, receiver) {
+ let value = Reflect.get(...arguments);
+ return typeof value == 'function' ? value.bind(target) : value;
+ }
+});
+
+alert(user.getName()); // Guest
+```
+
+That said, the solution has drawbacks, explained previously: it exposes the original object to the method, potentially allowing it to be passed further and breaking other proxied functionality.
+
+### Proxy != target
+
+Proxy and the original object are different objects. That's natural, right?
+
+So if we use the original object as a key, and then proxy it, then the proxy can't be found:
+
+```js run
+let allUsers = new Set();
+
+class User {
+ constructor(name) {
+ this.name = name;
+ allUsers.add(this);
+ }
+}
+
+let user = new User("John");
+
+alert(allUsers.has(user)); // true
+
+user = new Proxy(user, {});
+
+*!*
+alert(allUsers.has(user)); // false
+*/!*
+```
+
+As we can see, after proxying we can't find `user` in the set `allUsers`, because the proxy is a different object.
+
+```warn header="Proxies can't intercept a strict equality test `===`"
+Proxies can intercept many operators, such as `new` (with `construct`), `in` (with `has`), `delete` (with `deleteProperty`) and so on.
+
+But there's no way to intercept a strict equality test for objects. An object is strictly equal to itself only, and no other value.
+
+So all operations and built-in classes that compare objects for equality will differentiate between the object and the proxy. No transparent replacement here.
+```
+
+## Revocable proxies
+
+A *revocable* proxy is a proxy that can be disabled.
+
+Let's say we have a resource, and would like to close access to it any moment.
+
+What we can do is to wrap it into a revocable proxy, without any traps. Such proxy will forward operations to object, and we can disable it at any moment.
+
+The syntax is:
+
+```js
+let {proxy, revoke} = Proxy.revocable(target, handler)
+```
+
+The call returns an object with the `proxy` and `revoke` function to disable it.
+
+Here's an example:
+
+```js run
+let object = {
+ data: "Valuable data"
+};
+
+let {proxy, revoke} = Proxy.revocable(object, {});
+
+// pass the proxy somewhere instead of object...
+alert(proxy.data); // Valuable data
+
+// later in our code
+revoke();
+
+// the proxy isn't working any more (revoked)
+alert(proxy.data); // Error
+```
+
+A call to `revoke()` removes all internal references to the target object from the proxy, so they are no more connected. The target object can be garbage-collected after that.
+
+We can also store `revoke` in a `WeakMap`, to be able to easily find it by a proxy object:
+
+```js run
+*!*
+let revokes = new WeakMap();
+*/!*
+
+let object = {
+ data: "Valuable data"
+};
+
+let {proxy, revoke} = Proxy.revocable(object, {});
+
+revokes.set(proxy, revoke);
+
+// ..later in our code..
+revoke = revokes.get(proxy);
+revoke();
+
+alert(proxy.data); // Error (revoked)
+```
+
+The benefit of such approach is that we don't have to carry `revoke` around. We can get it from the map by `proxy` when needeed.
+
+Using `WeakMap` instead of `Map` here, because it should not block garbage collection. If a proxy object becomes "unreachable" (e.g. no variable references it any more), `WeakMap` allows it to be wiped from memory together with its `revoke` that we won't need any more.
+
+## References
+
+- Specification: [Proxy](https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots).
+- MDN: [Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy).
+
+## Summary
+
+`Proxy` is a wrapper around an object, that forwards operations on it to the object, optionally trapping some of them.
+
+It can wrap any kind of object, including classes and functions.
+
+The syntax is:
+
+```js
+let proxy = new Proxy(target, {
+ /* traps */
+});
+```
+
+...Then we should use `proxy` everywhere instead of `target`. A proxy doesn't have its own properties or methods. It traps an operation if the trap is provided, otherwise forwards it to `target` object.
+
+We can trap:
+- Reading (`get`), writing (`set`), deleting (`deleteProperty`) a property (even a non-existing one).
+- Calling a function (`apply` trap).
+- The `new` operator (`construct` trap).
+- Many other operations (the full list is at the beginning of the article and in the [docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)).
+
+That allows us to create "virtual" properties and methods, implement default values, observable objects, function decorators and so much more.
+
+We can also wrap an object multiple times in different proxies, decorating it with various aspects of functionality.
+
+The [Reflect](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect) API is designed to complement [Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy). For any `Proxy` trap, there's a `Reflect` call with same arguments. We should use those to forward calls to target objects.
+
+Proxies have some limitations:
+
+- Built-in objects have "internal slots", access to those can't be proxied. See the workaround above.
+- The same holds true for private class fields, as they are internally implemented using slots. So proxied method calls must have the target object as `this` to access them.
+- Object equality tests `===` can't be intercepted.
+- Performance: benchmarks depend on an engine, but generally accessing a property using a simplest proxy takes a few times longer. In practice that only matters for some "bottleneck" objects though.
diff --git a/1-js/99-js-misc/01-proxy/proxy-inherit-admin.svg b/1-js/99-js-misc/01-proxy/proxy-inherit-admin.svg
new file mode 100644
index 000000000..9ffe9a375
--- /dev/null
+++ b/1-js/99-js-misc/01-proxy/proxy-inherit-admin.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/99-js-misc/01-proxy/proxy-inherit.svg b/1-js/99-js-misc/01-proxy/proxy-inherit.svg
new file mode 100644
index 000000000..510dcef1b
--- /dev/null
+++ b/1-js/99-js-misc/01-proxy/proxy-inherit.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/99-js-misc/01-proxy/proxy.svg b/1-js/99-js-misc/01-proxy/proxy.svg
new file mode 100644
index 000000000..8aa14bdb8
--- /dev/null
+++ b/1-js/99-js-misc/01-proxy/proxy.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/99-js-misc/02-eval/1-eval-calculator/task.md b/1-js/99-js-misc/02-eval/1-eval-calculator/task.md
new file mode 100644
index 000000000..ece43ec9e
--- /dev/null
+++ b/1-js/99-js-misc/02-eval/1-eval-calculator/task.md
@@ -0,0 +1,11 @@
+importance: 4
+
+---
+
+# Eval-calculator
+
+Create a calculator that prompts for an arithmetic expression and returns its result.
+
+There's no need to check the expression for correctness in this task. Just evaluate and return the result.
+
+[demo]
diff --git a/1-js/99-js-misc/02-eval/article.md b/1-js/99-js-misc/02-eval/article.md
new file mode 100644
index 000000000..73e8424d1
--- /dev/null
+++ b/1-js/99-js-misc/02-eval/article.md
@@ -0,0 +1,114 @@
+# Eval: run a code string
+
+The built-in `eval` function allows to execute a string of code.
+
+The syntax is:
+
+```js
+let result = eval(code);
+```
+
+For example:
+
+```js run
+let code = 'alert("Hello")';
+eval(code); // Hello
+```
+
+A string of code may be long, contain line breaks, function declarations, variables and so on.
+
+The result of `eval` is the result of the last statement.
+
+For example:
+```js run
+let value = eval('1+1');
+alert(value); // 2
+```
+
+```js run
+let value = eval('let i = 0; ++i');
+alert(value); // 1
+```
+
+The eval'ed code is executed in the current lexical environment, so it can see outer variables:
+
+```js run no-beautify
+let a = 1;
+
+function f() {
+ let a = 2;
+
+*!*
+ eval('alert(a)'); // 2
+*/!*
+}
+
+f();
+```
+
+It can change outer variables as well:
+
+```js untrusted refresh run
+let x = 5;
+eval("x = 10");
+alert(x); // 10, value modified
+```
+
+In strict mode, `eval` has its own lexical environment. So functions and variables, declared inside eval, are not visible outside:
+
+```js untrusted refresh run
+// reminder: 'use strict' is enabled in runnable examples by default
+
+eval("let x = 5; function f() {}");
+
+alert(typeof x); // undefined (no such variable)
+// function f is also not visible
+```
+
+Without `use strict`, `eval` doesn't have its own lexical environment, so we would see `x` and `f` outside.
+
+## Using "eval"
+
+In modern programming `eval` is used very sparingly. It's often said that "eval is evil".
+
+The reason is simple: long, long time ago JavaScript was a much weaker language, many things could only be done with `eval`. But that time passed a decade ago.
+
+Right now, there's almost no reason to use `eval`. If someone is using it, there's a good chance they can replace it with a modern language construct or a [JavaScript Module](info:modules).
+
+Please note that its ability to access outer variables has side-effects.
+
+Code minifiers (tools used before JS gets to production, to compress it) replace local variables with shorter ones for optimization. That's usually safe, but not if `eval` is used, as it may reference them. So minifiers don't replace all local variables that might be visible from `eval`. That negatively affects code compression ratio.
+
+Using outer local variables inside `eval` is a bad programming practice, as it makes maintaining the code more difficult.
+
+There are two ways how to be totally safe from such problems.
+
+**If eval'ed code doesn't use outer variables, please call `eval` as `window.eval(...)`:**
+
+This way the code is executed in the global scope:
+
+```js untrusted refresh run
+let x = 1;
+{
+ let x = 5;
+ window.eval('alert(x)'); // 1 (global variable)
+}
+```
+
+**If eval'ed code needs local variables, change `eval` to `new Function` and pass them as arguments:**
+
+```js run
+let f = new Function('a', 'alert(a)');
+
+f(5); // 5
+```
+
+The `new Function` construct is explained in the chapter . It creates a function from a string, also in the global scope. So it can't see local variables. But it's so much clearer to pass them explicitly as arguments, like in the example above.
+
+## Summary
+
+A call to `eval(code)` runs the string of code and returns the result of the last statement.
+- Rarely used in modern JavaScript, as there's usually no need.
+- Can access outer local variables. That's considered bad practice.
+- Instead, to `eval` the code in the global scope, use `window.eval(code)`.
+- Or, if your code needs some data from the outer scope, use `new Function` and pass it as arguments.
diff --git a/1-js/99-js-misc/03-currying-partials/article.md b/1-js/99-js-misc/03-currying-partials/article.md
new file mode 100644
index 000000000..02f9a510d
--- /dev/null
+++ b/1-js/99-js-misc/03-currying-partials/article.md
@@ -0,0 +1,196 @@
+libs:
+ - lodash
+
+---
+
+# Currying
+
+[Currying](https://en.wikipedia.org/wiki/Currying) is an advanced technique of working with functions. It's used not only in JavaScript, but in other languages as well.
+
+Currying is a transformation of functions that translates a function from callable as `f(a, b, c)` into callable as `f(a)(b)(c)`.
+
+Currying doesn't call a function. It just transforms it.
+
+Let's see an example first, to better understand what we're talking about, and then practical applications.
+
+We'll create a helper function `curry(f)` that performs currying for a two-argument `f`. In other words, `curry(f)` for two-argument `f(a, b)` translates it into a function that runs as `f(a)(b)`:
+
+```js run
+*!*
+function curry(f) { // curry(f) does the currying transform
+ return function(a) {
+ return function(b) {
+ return f(a, b);
+ };
+ };
+}
+*/!*
+
+// usage
+function sum(a, b) {
+ return a + b;
+}
+
+let carriedSum = curry(sum);
+
+alert( carriedSum(1)(2) ); // 3
+```
+
+As you can see, the implementation is straightforward: it's just two wrappers.
+
+- The result of `curry(func)` is a wrapper `function(a)`.
+- When it is called like `sum(1)`, the argument is saved in the Lexical Environment, and a new wrapper is returned `function(b)`.
+- Then this wrapper is called with `2` as an argument, and it passes the call to the original `sum`.
+
+More advanced implementations of currying, such as [_.curry](https://lodash.com/docs#curry) from lodash library, return a wrapper that allows a function to be called both normally and partially:
+
+```js run
+function sum(a, b) {
+ return a + b;
+}
+
+let carriedSum = _.curry(sum); // using _.carry from lodash library
+
+alert( carriedSum(1, 2) ); // 3, still callable normally
+alert( carriedSum(1)(2) ); // 3, called partially
+```
+
+## Currying? What for?
+
+To understand the benefits we need a worthy real-life example.
+
+For instance, we have the logging function `log(date, importance, message)` that formats and outputs the information. In real projects such functions have many useful features like sending logs over the network, here we'll just use `alert`:
+
+```js
+function log(date, importance, message) {
+ alert(`[${date.getHours()}:${date.getMinutes()}] [${importance}] ${message}`);
+}
+```
+
+Let's curry it!
+
+```js
+log = _.curry(log);
+```
+
+After that `log` work normally:
+
+```js
+log(new Date(), "DEBUG", "some debug"); // log(a, b, c)
+```
+
+...But also works in the curried form:
+
+```js
+log(new Date())("DEBUG")("some debug"); // log(a)(b)(c)
+```
+
+Now we can easily make a convenience function for current logs:
+
+```js
+// logNow will be the partial of log with fixed first argument
+let logNow = log(new Date());
+
+// use it
+logNow("INFO", "message"); // [HH:mm] INFO message
+```
+
+Now `logNow` is `log` with fixed first argument, in other words "partially applied function" or "partial" for short.
+
+We can go further and make a convenience function for current debug logs:
+
+```js
+let debugNow = logNow("DEBUG");
+
+debugNow("message"); // [HH:mm] DEBUG message
+```
+
+So:
+1. We didn't lose anything after currying: `log` is still callable normally.
+2. We can easily generate partial functions such as for today's logs.
+
+## Advanced curry implementation
+
+In case you'd like to get in details, here's the "advanced" curry implementation for multi-argument functions that we could use above.
+
+It's pretty short:
+
+```js
+function curry(func) {
+
+ return function curried(...args) {
+ if (args.length >= func.length) {
+ return func.apply(this, args);
+ } else {
+ return function(...args2) {
+ return curried.apply(this, args.concat(args2));
+ }
+ }
+ };
+
+}
+```
+
+Usage examples:
+
+```js
+function sum(a, b, c) {
+ return a + b + c;
+}
+
+let curriedSum = curry(sum);
+
+alert( curriedSum(1, 2, 3) ); // 6, still callable normally
+alert( curriedSum(1)(2,3) ); // 6, currying of 1st arg
+alert( curriedSum(1)(2)(3) ); // 6, full currying
+```
+
+The new `curry` may look complicated, but it's actually easy to understand.
+
+The result of `curry(func)` call is the wrapper `curried` that looks like this:
+
+```js
+// func is the function to transform
+function curried(...args) {
+ if (args.length >= func.length) { // (1)
+ return func.apply(this, args);
+ } else {
+ return function pass(...args2) { // (2)
+ return curried.apply(this, args.concat(args2));
+ }
+ }
+};
+```
+
+When we run it, there are two `if` execution branches:
+
+1. Call now: if passed `args` count is the same as the original function has in its definition (`func.length`) or longer, then just pass the call to it.
+2. Get a partial: otherwise, `func` is not called yet. Instead, another wrapper `pass` is returned, that will re-apply `curried` providing previous arguments together with the new ones. Then on a new call, again, we'll get either a new partial (if not enough arguments) or, finally, the result.
+
+For instance, let's see what happens in the case of `sum(a, b, c)`. Three arguments, so `sum.length = 3`.
+
+For the call `curried(1)(2)(3)`:
+
+1. The first call `curried(1)` remembers `1` in its Lexical Environment, and returns a wrapper `pass`.
+2. The wrapper `pass` is called with `(2)`: it takes previous args (`1`), concatenates them with what it got `(2)` and calls `curried(1, 2)` with them together. As the argument count is still less than 3, `curry` returns `pass`.
+3. The wrapper `pass` is called again with `(3)`, for the next call `pass(3)` takes previous args (`1`, `2`) and adds `3` to them, making the call `curried(1, 2, 3)` -- there are `3` arguments at last, they are given to the original function.
+
+If that's still not obvious, just trace the calls sequence in your mind or on the paper.
+
+```smart header="Fixed-length functions only"
+The currying requires the function to have a fixed number of arguments.
+
+A function that uses rest parameters, such as `f(...args)`, can't be curried this way.
+```
+
+```smart header="A little more than currying"
+By definition, currying should convert `sum(a, b, c)` into `sum(a)(b)(c)`.
+
+But most implementations of currying in JavaScript are advanced, as described: they also keep the function callable in the multi-argument variant.
+```
+
+## Summary
+
+*Currying* is a transform that makes `f(a,b,c)` callable as `f(a)(b)(c)`. JavaScript implementations usually both keep the function callable normally and return the partial if arguments count is not enough.
+
+Currying allows to easily get partials. As we've seen in the logging example: the universal function `log(date, importance, message)` after currying gives us partials when called with one argument like `log(date)` or two arguments `log(date, importance)`.
diff --git a/2-ui/1-document/01-browser-environment/article.md b/2-ui/1-document/01-browser-environment/article.md
index 0e123f581..974142761 100644
--- a/2-ui/1-document/01-browser-environment/article.md
+++ b/2-ui/1-document/01-browser-environment/article.md
@@ -94,11 +94,18 @@ if (confirm("Go to wikipedia?")) {
Functions `alert/confirm/prompt` are also a part of BOM: they are directly not related to the document, but represent pure browser methods of communicating with the user.
+<<<<<<< HEAD
```smart header="HTML specification"
BOM is the part of the general [HTML specification](https://html.spec.whatwg.org).
Yes, you heard that right. The HTML spec at is not only about the "HTML language" (tags, attributes), but also covers a bunch of objects, methods and browser-specific DOM extensions. That's "HTML in broad terms".
+=======
+```smart header="Specifications"
+BOM is the part of the general [HTML specification](https://html.spec.whatwg.org).
+
+Yes, you heard that right. The HTML spec at is not only about the "HTML language" (tags, attributes), but also covers a bunch of objects, methods and browser-specific DOM extensions. That's "HTML in broad terms". Also, some parts have additional specs listed at .
+>>>>>>> 852ee189170d9022f67ab6d387aeae76810b5923
```
## Summary
diff --git a/2-ui/2-events/05-dispatch-events/article.md b/2-ui/2-events/05-dispatch-events/article.md
index 2b13d2360..e0e9c58b7 100644
--- a/2-ui/2-events/05-dispatch-events/article.md
+++ b/2-ui/2-events/05-dispatch-events/article.md
@@ -2,9 +2,9 @@
We can not only assign handlers, but also generate events from JavaScript.
-Custom events can be used to create "graphical components". For instance, a root element of the menu may trigger events telling what happens with the menu: `open` (menu open), `select` (an item is selected) and so on.
+Custom events can be used to create "graphical components". For instance, a root element of our own JS-based menu may trigger events telling what happens with the menu: `open` (menu open), `select` (an item is selected) and so on. Another code may listen to the events and observe what's happening with the menu.
-Also we can generate built-in events like `click`, `mousedown` etc, that may be good for testing.
+We can generate not only completely new events, that we invent for our own purposes, but also built-in ones, such as `click`, `mousedown` etc. That may be helpful for automated testing.
## Event constructor
@@ -27,9 +27,9 @@ Arguments:
## dispatchEvent
-After an event object is created, we should "run" it on an element using the call `elem.dispatchEvent(event)`.
+After an event object is created, we should "run" it on an element using the call `elem.dispatchEvent(event)`.
-Then handlers react on it as if it were a regular built-in event. If the event was created with the `bubbles` flag, then it bubbles.
+Then handlers react on it as if it were a regular browser event. If the event was created with the `bubbles` flag, then it bubbles.
In the example below the `click` event is initiated in JavaScript. The handler works same way as if the button was clicked:
@@ -125,11 +125,11 @@ alert(event.clientX); // undefined, the unknown property is ignored!
Technically, we can work around that by assigning directly `event.clientX=100` after creation. So that's a matter of convenience and following the rules. Browser-generated events always have the right type.
-The full list of properties for different UI events is in the specification, for instance [MouseEvent](https://www.w3.org/TR/uievents/#mouseevent).
+The full list of properties for different UI events is in the specification, for instance, [MouseEvent](https://www.w3.org/TR/uievents/#mouseevent).
## Custom events
-For our own, custom events like `"hello"` we should use `new CustomEvent`. Technically [CustomEvent](https://dom.spec.whatwg.org/#customevent) is the same as `Event`, with one exception.
+For our own, completely new events types like `"hello"` we should use `new CustomEvent`. Technically [CustomEvent](https://dom.spec.whatwg.org/#customevent) is the same as `Event`, with one exception.
In the second argument (object) we can add an additional property `detail` for any custom information that we want to pass with the event.
@@ -154,25 +154,33 @@ For instance:
The `detail` property can have any data. Technically we could live without, because we can assign any properties into a regular `new Event` object after its creation. But `CustomEvent` provides the special `detail` field for it to evade conflicts with other event properties.
-The event class tells something about "what kind of event" it is, and if the event is custom, then we should use `CustomEvent` just to be clear about what it is.
+Besides, the event class describes "what kind of event" it is, and if the event is custom, then we should use `CustomEvent` just to be clear about what it is.
## event.preventDefault()
-We can call `event.preventDefault()` on a script-generated event if `cancelable:true` flag is specified.
+Many browser events have a "default action", such as nagivating to a link, starting a selection, and so on.
+<<<<<<< HEAD
Of course, if the event has a non-standard name, then it's not known to the browser, and there's no "default browser action" for it.
But the event-generating code may plan some actions after `dispatchEvent`.
The call of `event.preventDefault()` is a way for the handler to send a signal that those actions shouldn't be performed.
+=======
+For new, custom events, there are definitely no default browser actions, but a code that dispatches such event may have its own plans what to do after triggering the event.
-In that case the call to `elem.dispatchEvent(event)` returns `false`. And the event-generating code knows that the processing shouldn't continue.
+By calling `event.preventDefault()`, an event handler may send a signal that those actions should be canceled.
+>>>>>>> 852ee189170d9022f67ab6d387aeae76810b5923
-For instance, in the example below there's a `hide()` function. It generates the `"hide"` event on the element `#rabbit`, notifying all interested parties that the rabbit is going to hide.
+In that case the call to `elem.dispatchEvent(event)` returns `false`. And the code that dispatched it knows that it shouldn't continue.
-A handler set by `rabbit.addEventListener('hide',...)` will learn about that and, if it wants, can prevent that action by calling `event.preventDefault()`. Then the rabbit won't hide:
+Let's see a practical example - a hiding rabbit (could be a closing menu or something else).
-```html run refresh
+Below you can see a `#rabbit` and `hide()` function that dispatches `"hide"` event on it, to let all interested parties know that the rabbit is going to hide.
+
+Any handler can listen to that event with `rabbit.addEventListener('hide',...)` and, if needed, cancel the action using `event.preventDefault()`. Then the rabbit won't disappear:
+
+```html run refresh autorun
|\ /|
\|_|/
@@ -180,6 +188,7 @@ A handler set by `rabbit.addEventListener('hide',...)` will learn about that and
=\_Y_/=
{>o<}
+
```
+Обратите внимание: событие должно иметь флаг `cancelable: true`, иначе вызов `event.preventDefault()` будет проигнорирован.
## Events-in-events are synchronous
@@ -217,11 +223,10 @@ Then the control jumps to the nested event handler, and after it goes back.
For instance, here the nested `menu-open` event is processed synchronously, during the `onclick`:
-```html run
+```html run autorun
```
-Please note that the nested event `menu-open` bubbles up and is handled on the `document`. The propagation of the nested event is fully finished before the processing gets back to the outer code (`onclick`).
+The output order is: 1 -> nested -> 2.
+
+Please note that the nested event `menu-open` fully bubbles up and is handled on the `document`. The propagation and handling of the nested event must be fully finished before the processing gets back to the outer code (`onclick`).
That's not only about `dispatchEvent`, there are other cases. JavaScript in an event handler can call methods that lead to other events -- they are too processed synchronously.
+<<<<<<< HEAD
If we don't like it, we can either put the `dispatchEvent` (or other event-triggering call) at the end of `onclick` or, if inconvenient, wrap it in `setTimeout(...,0)`:
+=======
+If we don't like it, we can either put the `dispatchEvent` (or other event-triggering call) at the end of `onclick` or, maybe better, wrap it in zero-delay `setTimeout`:
+>>>>>>> 852ee189170d9022f67ab6d387aeae76810b5923
```html run
```
+<<<<<<< HEAD
+=======
+Now `dispatchEvent` runs asynchronously after the current code execution is finished, including `mouse.onclick`, so event handlers are totally separate.
+
+The output order becomes: 1 -> 2 -> nested.
+
+>>>>>>> 852ee189170d9022f67ab6d387aeae76810b5923
## Summary
To generate an event, we first need to create an event object.
The generic `Event(name, options)` constructor accepts an arbitrary event name and the `options` object with two properties:
- - `bubbles: true` if the event should bubble.
- - `cancelable: true` if the `event.preventDefault()` should work.
+- `bubbles: true` if the event should bubble.
+- `cancelable: true` if the `event.preventDefault()` should work.
Other constructors of native events like `MouseEvent`, `KeyboardEvent` and so on accept properties specific to that event type. For instance, `clientX` for mouse events.
diff --git a/2-ui/3-event-details/1-mouse-events-basics/01-selectable-list/task.md b/2-ui/3-event-details/1-mouse-events-basics/01-selectable-list/task.md
index f358616ef..8d29134ff 100644
--- a/2-ui/3-event-details/1-mouse-events-basics/01-selectable-list/task.md
+++ b/2-ui/3-event-details/1-mouse-events-basics/01-selectable-list/task.md
@@ -14,4 +14,5 @@ The demo:
[iframe border="1" src="solution" height=180]
P.S. For this task we can assume that list items are text-only. No nested tags.
+
P.P.S. Prevent the native browser selection of the text on clicks.
diff --git a/2-ui/3-event-details/1-mouse-events-basics/article.md b/2-ui/3-event-details/1-mouse-events-basics/article.md
index dce1ad3de..14233fcca 100644
--- a/2-ui/3-event-details/1-mouse-events-basics/article.md
+++ b/2-ui/3-event-details/1-mouse-events-basics/article.md
@@ -1,9 +1,9 @@
# Mouse events basics
-Mouse events come not only from "mouse manipulators", but are also emulated on touch devices, to make them compatible.
-
In this chapter we'll get into more details about mouse events and their properties.
+Please note: such events may come not only from "mouse devices", but are also from other devices, such as phones and tablets, where they are emulated for compatibility.
+
## Mouse event types
We can split mouse events into two categories: "simple" and "complex"
@@ -42,7 +42,7 @@ An action may trigger multiple events.
For instance, a click first triggers `mousedown`, when the button is pressed, then `mouseup` and `click` when it's released.
-In cases when a single action initiates multiple events, their order is fixed. That is, the handlers are called in the order `mousedown` -> `mouseup` -> `click`. Events are handled in the same sequence: `onmouseup` finishes before `onclick` runs.
+In cases when a single action initiates multiple events, their order is fixed. That is, the handlers are called in the order `mousedown` -> `mouseup` -> `click`.
```online
Click the button below and you'll see the events. Try double-click too.
@@ -74,12 +74,14 @@ The middle button is somewhat exotic right now and is very rarely used.
All mouse events include the information about pressed modifier keys.
-The properties are:
+Event properties:
+
+- `shiftKey`: `key:Shift`
+- `altKey`: `key:Alt` (or `key:Opt` for Mac)
+- `ctrlKey`: `key:Ctrl`
+- `metaKey`: `key:Cmd` for Mac
-- `shiftKey`
-- `altKey`
-- `ctrlKey`
-- `metaKey` (`key:Cmd` for Mac)
+They are `true` if the corresponding key was pressed during the event.
For instance, the button below only works on `key:Alt+Shift`+click:
@@ -98,15 +100,17 @@ For instance, the button below only works on `key:Alt+Shift`+click:
```
```warn header="Attention: on Mac it's usually `Cmd` instead of `Ctrl`"
-On Windows and Linux there are modifier keys `key:Alt`, `key:Shift` and `key:Ctrl`. On Mac there's one more: `key:Cmd`, it corresponds to the property `metaKey`.
+On Windows and Linux there are modifier keys `key:Alt`, `key:Shift` and `key:Ctrl`. On Mac there's one more: `key:Cmd`, corresponding to the property `metaKey`.
-In most cases when Windows/Linux uses `key:Ctrl`, on Mac people use `key:Cmd`. So where a Windows user presses `key:Ctrl+Enter` or `key:Ctrl+A`, a Mac user would press `key:Cmd+Enter` or `key:Cmd+A`, and so on, most apps use `key:Cmd` instead of `key:Ctrl`.
+In most applications, when Windows/Linux uses `key:Ctrl`, on Mac `key:Cmd` is used.
-So if we want to support combinations like `key:Ctrl`+click, then for Mac it makes sense to use `key:Cmd`+click. That's more comfortable for Mac users.
+That is: where a Windows user presses `key:Ctrl+Enter` or `key:Ctrl+A`, a Mac user would press `key:Cmd+Enter` or `key:Cmd+A`, and so on.
-Even if we'd like to force Mac users to `key:Ctrl`+click -- that's kind of difficult. The problem is: a left-click with `key:Ctrl` is interpreted as a *right-click* on Mac, and it generates the `contextmenu` event, not `click` like Windows/Linux.
+So if we want to support combinations like `key:Ctrl`+click, then for Mac it makes sense to use `key:Cmd`+click. That's more comfortable for Mac users.
-So if we want users of all operational systems to feel comfortable, then together with `ctrlKey` we should use `metaKey`.
+Even if we'd like to force Mac users to `key:Ctrl`+click -- that's kind of difficult. The problem is: a left-click with `key:Ctrl` is interpreted as a *right-click* on MacOS, and it generates the `contextmenu` event, not `click` like Windows/Linux.
+
+So if we want users of all operational systems to feel comfortable, then together with `ctrlKey` we should check `metaKey`.
For JS-code it means that we should check `if (event.ctrlKey || event.metaKey)`.
```
@@ -126,60 +130,38 @@ All mouse events have coordinates in two flavours:
For instance, if we have a window of the size 500x500, and the mouse is in the left-upper corner, then `clientX` and `clientY` are `0`. And if the mouse is in the center, then `clientX` and `clientY` are `250`, no matter what place in the document it is. They are similar to `position:fixed`.
````online
-Move the mouse over the input field to see `clientX/clientY` (it's in the `iframe`, so coordinates are relative to that `iframe`):
+Move the mouse over the input field to see `clientX/clientY` (the example is in the `iframe`, so coordinates are relative to that `iframe`):
```html autorun height=50
```
````
-Document-relative coordinates are counted from the left-upper corner of the document, not the window.
-Coordinates `pageX`, `pageY` are similar to `position:absolute` on the document level.
+Document-relative coordinates `pageX`, `pageY` are counted from the left-upper corner of the document, not the window. You can read more about coordinates in the chapter .
-You can read more about coordinates in the chapter .
+## Disabling selection
+<<<<<<< HEAD
## No selection on mousedown
Mouse clicks have a side-effect that may be disturbing. A double click selects the text.
If we want to handle click events ourselves, then the "extra" selection doesn't look good.
+=======
+Double mouse click has a side-effect that may be disturbing in some interfaces: it selects the text.
+>>>>>>> 852ee189170d9022f67ab6d387aeae76810b5923
For instance, a double-click on the text below selects it in addition to our handler:
```html autorun height=50
-Double-click me
+Double-click me
```
-There's a CSS way to stop the selection: the `user-select` property from [CSS UI Draft](https://www.w3.org/TR/css-ui-4/).
+If one presses the left mouse button and, without releasing it, moves the mouse, that also makes the selection, often unwanted.
-Most browsers support it with prefixes:
+There are multiple ways to prevent the selection, that you can read in the chapter .
-```html autorun height=50
-
-
-Before...
-
- Unselectable
-
-...After
-```
-
-Now if you double-click on "Unselectable", it doesn't get selected. Seems to work.
-
-...But there is a potential problem! The text became truly unselectable. Even if a user starts the selection from "Before" and ends with "After", the selection skips "Unselectable" part. Do we really want to make our text unselectable?
-
-Most of time, we don't. A user may have valid reasons to select the text, for copying or other needs. That may be inconvenient if we don't allow them to do it. So this solution is not that good.
-
-What we want is to prevent the selection on double-click, that's it.
-
-A text selection is the default browser action on `mousedown` event. So the alternative solution would be to handle `mousedown` and prevent it, like this:
+In this particular case the most reasonable way is to prevent the browser action on `mousedown`. It prevents both these selections:
```html autorun height=50
Before...
@@ -189,6 +171,7 @@ Before...
...After
```
+<<<<<<< HEAD
Now the bold element is not selected on double clicks.
The text inside it is still selectable. However, the selection should start not on the text itself, but before or after it. Usually that's fine though.
@@ -205,12 +188,14 @@ Before...
...After
```
+=======
+Now the bold element is not selected on double clicks, and pressing the left button on it won't start the selection.
+>>>>>>> 852ee189170d9022f67ab6d387aeae76810b5923
-If you double-click on the bold element, then the selection appears and then is immediately removed. That doesn't look nice though.
-````
+Please note: the text inside it is still selectable. However, the selection should start not on the text itself, but before or after it. Usually that's fine for users.
````smart header="Preventing copying"
-If we want to disable selection to protect our content from copy-pasting, then we can use another event: `oncopy`.
+If we want to disable selection to protect our page content from copy-pasting, then we can use another event: `oncopy`.
```html autorun height=80 no-beautify