From 0a2b9361334fe7c8064f8d64068566e6af44ed80 Mon Sep 17 00:00:00 2001 From: Ilya Kantor Date: Sun, 24 Sep 2017 08:58:52 +0300 Subject: [PATCH] fixes --- 1-js/03-code-quality/04-ninja-code/article.md | 4 +- 1-js/03-code-quality/06-polyfills/article.md | 2 +- 1-js/04-object-basics/01-object/article.md | 6 +- 1-js/04-object-basics/03-symbol/article.md | 57 ++++++++++--------- .../04-function-prototype/article.md | 6 +- 5 files changed, 41 insertions(+), 34 deletions(-) diff --git a/1-js/03-code-quality/04-ninja-code/article.md b/1-js/03-code-quality/04-ninja-code/article.md index 0b97b3ff..58bd9c2c 100644 --- a/1-js/03-code-quality/04-ninja-code/article.md +++ b/1-js/03-code-quality/04-ninja-code/article.md @@ -70,7 +70,7 @@ While choosing a name try to use the most abstract word. Like `obj`, `data`, `va ...But what to do if `data` is already taken? Try `value`, it's also universal. After all, a variable eventually gets a *value*. -- **Name the variable by its type: `str`, `num`...** +- **Name a variable by its type: `str`, `num`...** Give them a try. A young ninja may wonder -- do such names make the code worse? Actually, yes! @@ -78,7 +78,7 @@ While choosing a name try to use the most abstract word. Like `obj`, `data`, `va Indeed, the value type is easy to find out by debugging. But what's the meaning of the variable? Which string/number does it store? There's just no way to figure out without a good meditation! -- **...But what if there are no more such names?** Just add a letter: `item1, item2, elem5, data1`... +- **...But what if there are no more such names?** Just add a number: `data1, item2, elem5`... ## Attention test diff --git a/1-js/03-code-quality/06-polyfills/article.md b/1-js/03-code-quality/06-polyfills/article.md index 37ea9f89..caf0826c 100644 --- a/1-js/03-code-quality/06-polyfills/article.md +++ b/1-js/03-code-quality/06-polyfills/article.md @@ -46,7 +46,7 @@ alert('Press the "Play" button in the upper-right corner to run'); ``` Examples that use modern JS will work only if your browser supports it. -``` +```` ```offline As you're reading the offline version, examples are not runnable. But they usually work :) diff --git a/1-js/04-object-basics/01-object/article.md b/1-js/04-object-basics/01-object/article.md index abb93ea4..74586d6b 100644 --- a/1-js/04-object-basics/01-object/article.md +++ b/1-js/04-object-basics/01-object/article.md @@ -222,7 +222,11 @@ obj.__proto__ = 5; alert(obj.__proto__); // [object Object], didn't work as intended ``` -As we see from the code, the assignment to a primitive `5` is ignored. If we want to store *arbitrary* (user-provided) keys, then such behavior can be the source of bugs and even vulnerabilities, because it's unexpected. There's another data structure [Map](info:map-set-weakmap-weakset), that we'll learn in the chapter , which supports arbitrary keys. +As we see from the code, the assignment to a primitive `5` is ignored. + +That can be come a source of bugs and even vulnerabilies if we intent to store arbitrary key-value pairs in an object, and allow a visitor to specify the keys. In that case the visitor may choose "__proto__" as the key, and the assignment logic will be ruined (as shown above). + +There's another data structure [Map](info:map-set-weakmap-weakset), that we'll learn in the chapter , which supports arbitrary keys. Also there's a way to make objects treat `__proto__` as a regular property, but first we need to know more about objects to understand it. ```` diff --git a/1-js/04-object-basics/03-symbol/article.md b/1-js/04-object-basics/03-symbol/article.md index 47fdc28b..54eb612b 100644 --- a/1-js/04-object-basics/03-symbol/article.md +++ b/1-js/04-object-basics/03-symbol/article.md @@ -9,18 +9,25 @@ Till now we've only seen strings. Now let's see the advantages that symbols can ## Symbols -"Symbol" value represents an unique identifier with a given name. +"Symbol" value represents an unique identifier. -A value of this type can be created using `Symbol(name)`: +A value of this type can be created using `Symbol()`: ```js -// id is a symbol with the name "id" +// id is a new symbol +let id = Symbol(); +``` + +We can also give symbol a description (also called a symbol name), mostly useful for debugging purposes: + +```js +// id is a symbol with the description "id" let id = Symbol("id"); ``` -Symbols are guaranteed to be unique. Even if we create many symbols with the same name, they are different values. +Symbols are guaranteed to be unique. Even if we create many symbols with the same description, they are different values. The description is just a label that doesn't affect anything. -For instance, here are two symbols with the same name -- they are not equal: +For instance, here are two symbols with the same description -- they are not equal: ```js run let id1 = Symbol("id"); @@ -56,13 +63,11 @@ alert(id.toString()); // Symbol(id), now it works That's a "language guard" against messing up, because strings and symbols are fundamentally different and should not occasionally convert one into another. ```` - - ## "Hidden" properties Symbols allow us to create "hidden" properties of an object, that no other part of code can occasionally access or overwrite. -For instance, if we want to store an "identifier" for the object `user`, we can create a symbol with the name `id` for it: +For instance, if we want to store an "identifier" for the object `user`, we can use a symbol as a key for it: ```js run let user = { name: "John" }; @@ -72,11 +77,13 @@ user[id] = "ID Value"; alert( user[id] ); // we can access the data using the symbol as the key ``` -Now let's imagine that another script wants to have its own "id" property inside `user`, for its own purposes. That may be another JavaScript library, so the scripts are completely unaware of each other. +What's the benefit over using `Symbol("id")` over a string `"id"`? -No problem. It can create its own `Symbol("id")`. +Let's make the example a bit deeper to see that. -The script: +Imagine that another script wants to have its own "id" property inside `user`, for its own purposes. That may be another JavaScript library, so the scripts are completely unaware of each other. + +Then that script can create its own `Symbol("id")`, like this: ```js // ... @@ -87,7 +94,7 @@ user[id] = "Their id value"; There will be no conflict, because symbols are always different, even if they have the same name. -Please note that if we used a string `"id"` instead of a symbol for the same purpose, then there *would* be a conflict: +Now note that if we used a string `"id"` instead of a symbol for the same purpose, then there *would* be a conflict: ```js run let user = { name: "John" }; @@ -176,25 +183,27 @@ alert( obj[0] ); // test (same property) ## Global symbols -As we've seen, usually all symbols are different, even if they have the same name. But sometimes we want same-named symbols to be the same entities. +As we've seen, usually all symbols are different, even if they have the same names. But sometimes we want same-named symbols to be same entities. For instance, different parts of our application want to access symbol `"id"` meaning exactly the same property. To achieve that, there exists a *global symbol registry*. We can create symbols in it and access them later, and it guarantees that repeated accesses by the same name return exactly the same symbol. -In order to create or read a symbol in the registry, use `Symbol.for(name)`. +In order to create or read a symbol in the registry, use `Symbol.for(key)`. + +That call checks the global registry, and if there's a symbol described as `key`, then returns it, otherwise creates a new symbol `Symbol(key)` and stores it in the registry by the given `key`. For instance: ```js run // read from the global registry -let name = Symbol.for("name"); // if the symbol did not exist, it is created +let id = Symbol.for("id"); // if the symbol did not exist, it is created // read it again -let nameAgain = Symbol.for("name"); +let idAgain = Symbol.for("id"); // the same symbol -alert( name === nameAgain ); // true +alert( id === idAgain ); // true ``` Symbols inside the registry are called *global symbols*. If we want an application-wide symbol, accessible everywhere in the code -- that's what they are for. @@ -207,7 +216,7 @@ In JavaScript, as we can see, that's right for global symbols. ### Symbol.keyFor -For global symbols, not only `Symbol.for(name)` returns a symbol by name, but there's a reverse call: `Symbol.keyFor(sym)`, that does the reverse: returns a name by a global symbol. +For global symbols, not only `Symbol.for(key)` returns a symbol by name, but there's a reverse call: `Symbol.keyFor(sym)`, that does the reverse: returns a name by a global symbol. For instance: @@ -220,20 +229,16 @@ alert( Symbol.keyFor(sym) ); // name alert( Symbol.keyFor(sym2) ); // id ``` -The `Symbol.keyFor` internally uses the global symbol registry to look up the name for the symbol. So it doesn't work for non-global symbols. If the symbol is not global, it won't be able to find it and return `undefined`. +The `Symbol.keyFor` internally uses the global symbol registry to look up the key for the symbol. So it doesn't work for non-global symbols. If the symbol is not global, it won't be able to find it and return `undefined`. For instance: ```js run alert( Symbol.keyFor(Symbol.for("name")) ); // name, global symbol -alert( Symbol.keyFor(Symbol("name2")) ); // undefined, non-global symbol +alert( Symbol.keyFor(Symbol("name2")) ); // undefined, the argument isn't a global symbol ``` -So, for global symbols the name may be indeed helpful, as we can get a symbol by id. - -And for non-global symbols the name is only used for debugging purposes, like printing out a symbol. - ## System symbols There exist many "system" symbols that JavaScript uses internally, and we can use them to fine-tune various aspects of our objects. @@ -254,9 +259,9 @@ Other symbols will also become familiar when we study the corresponding language `Symbol` is a primitive type for unique identifiers. -Symbols are created with `Symbol(name)` call. +Symbols are created with `Symbol()` call with an optional description. -Symbols are always different values, even if they have the same name. If we want same-named symbols to be equal, then we should use the global registry: `Symbol.for(name)` returns (creates if needed) a global symbol with the given name. Multiple calls of `Symbol.for` return exactly the same symbol. +Symbols are always different values, even if they have the same name. If we want same-named symbols to be equal, then we should use the global registry: `Symbol.for(key)` returns (creates if needed) a global symbol with `key` as the name. Multiple calls of `Symbol.for` return exactly the same symbol. Symbols have two main use cases: diff --git a/1-js/07-object-oriented-programming/04-function-prototype/article.md b/1-js/07-object-oriented-programming/04-function-prototype/article.md index e002014f..4abc4095 100644 --- a/1-js/07-object-oriented-programming/04-function-prototype/article.md +++ b/1-js/07-object-oriented-programming/04-function-prototype/article.md @@ -1,6 +1,6 @@ # F.prototype -In modern JavaScript we can set a prototype using `__proto__`. But it wasn't like that all the time. +In modern JavaScript we can set a prototype using `__proto__`, as described in the previous article. But it wasn't like that all the time. [cut] @@ -10,9 +10,7 @@ But in the old times, there was another (and the only) way to set it: to use a ` ## The "prototype" property -As we know already, `new F()` creates a new object. But what we didn't use yet `F.prototype` property. - -That property is used by the JavaScript itself to set `[[Prototype]]` for new objects. +As we know already, `new F()` creates a new object. In the process, its "magic" `F.prototype` property is used by the JavaScript itself to set `[[Prototype]]` for new objects. **When a new object is created with `new F()`, the object's `[[Prototype]]` is set to `F.prototype`.**