From 7267abd41b1125d16f1c72204df2a161267c545b Mon Sep 17 00:00:00 2001 From: Andry <47834618+nikandev@users.noreply.github.com> Date: Sun, 28 Aug 2022 12:52:32 +0300 Subject: [PATCH 01/43] Update article.md Adds missing comma on line 24 --- 5-network/06-fetch-api/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/5-network/06-fetch-api/article.md b/5-network/06-fetch-api/article.md index c3f75175f..16e2705f0 100644 --- a/5-network/06-fetch-api/article.md +++ b/5-network/06-fetch-api/article.md @@ -21,7 +21,7 @@ let promise = fetch(url, { // depending on the request body "Content-Type": "text/plain;charset=UTF-8" }, - body: undefined // string, FormData, Blob, BufferSource, or URLSearchParams + body: undefined, // string, FormData, Blob, BufferSource, or URLSearchParams referrer: "about:client", // or "" to send no Referer header, // or an url from the current origin referrerPolicy: "no-referrer-when-downgrade", // no-referrer, origin, same-origin... From c11e773e70e1383f72381444c359e7d2021343e3 Mon Sep 17 00:00:00 2001 From: Eddie <36518273+0xEddie@users.noreply.github.com> Date: Sun, 28 Aug 2022 10:54:03 -0600 Subject: [PATCH 02/43] Clarify instructions of `read` method --- .../06-constructor-new/2-calculator-constructor/task.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/task.md b/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/task.md index 60e7c373e..490a42762 100644 --- a/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/task.md +++ b/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/task.md @@ -6,7 +6,7 @@ importance: 5 Create a constructor function `Calculator` that creates objects with 3 methods: -- `read()` asks for two values using `prompt` and remembers them in object properties. +- `read()` asks for two values using `prompt` and stores each of them in a unique object property. - `sum()` returns the sum of these properties. - `mul()` returns the multiplication product of these properties. From e09ea79a3b52c55f07a75b39071f1f1691315c3b Mon Sep 17 00:00:00 2001 From: Eddie <36518273+0xEddie@users.noreply.github.com> Date: Sun, 28 Aug 2022 16:07:53 -0600 Subject: [PATCH 03/43] Update task.md --- .../06-constructor-new/2-calculator-constructor/task.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/task.md b/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/task.md index 490a42762..c862bec40 100644 --- a/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/task.md +++ b/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/task.md @@ -6,7 +6,7 @@ importance: 5 Create a constructor function `Calculator` that creates objects with 3 methods: -- `read()` asks for two values using `prompt` and stores each of them in a unique object property. +- `read()` prompts for two values and saves them as object properties with names `a` and `b` respectively. - `sum()` returns the sum of these properties. - `mul()` returns the multiplication product of these properties. From a0d6b529711b17929577ac9df2304a17e91a9075 Mon Sep 17 00:00:00 2001 From: KilianSorel <104085267+KilianSorel@users.noreply.github.com> Date: Tue, 30 Aug 2022 06:49:31 +0000 Subject: [PATCH 04/43] Fix typo --- .../1-generators/01-pseudo-random-generator/solution.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/solution.md b/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/solution.md index af2ad0eed..4355d0cfc 100644 --- a/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/solution.md +++ b/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/solution.md @@ -3,7 +3,7 @@ function* pseudoRandom(seed) { let value = seed; while(true) { - value = value * 16807 % 2147483647 + value = value * 16807 % 2147483647; yield value; } From 5abfab904595b6d645770d3fa639a1d9b2bad113 Mon Sep 17 00:00:00 2001 From: Dave Mackey Date: Tue, 6 Sep 2022 09:01:26 -0400 Subject: [PATCH 05/43] Minor grammar --- 2-ui/2-events/01-introduction-browser-events/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/2-ui/2-events/01-introduction-browser-events/article.md b/2-ui/2-events/01-introduction-browser-events/article.md index f75f6c11f..764b24b34 100644 --- a/2-ui/2-events/01-introduction-browser-events/article.md +++ b/2-ui/2-events/01-introduction-browser-events/article.md @@ -24,7 +24,7 @@ Here's a list of the most useful DOM events, just to take a look at: **CSS events:** - `transitionend` -- when a CSS-animation finishes. -There are many other events. We'll get into more details of particular events in next chapters. +There are many other events. We'll get into more details of particular events in upcoming chapters. ## Event handlers From a6f19fb3ed502e2a6987fb7ef35f2dd83a92e07d Mon Sep 17 00:00:00 2001 From: Dave Mackey Date: Tue, 6 Sep 2022 09:13:22 -0400 Subject: [PATCH 06/43] Update article.md Minor changes to grammar --- 2-ui/2-events/01-introduction-browser-events/article.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/2-ui/2-events/01-introduction-browser-events/article.md b/2-ui/2-events/01-introduction-browser-events/article.md index f75f6c11f..2e41b640b 100644 --- a/2-ui/2-events/01-introduction-browser-events/article.md +++ b/2-ui/2-events/01-introduction-browser-events/article.md @@ -195,7 +195,7 @@ Assign a handler to `elem.onclick`, not `elem.ONCLICK`, because DOM properties a ## addEventListener -The fundamental problem of the aforementioned ways to assign handlers -- we can't assign multiple handlers to one event. +The fundamental problem of the aforementioned ways to assign handlers is that we *can't assign multiple handlers to one event*. Let's say, one part of our code wants to highlight a button on click, and another one wants to show a message on the same click. @@ -207,7 +207,7 @@ input.onclick = function() { alert(1); } input.onclick = function() { alert(2); } // replaces the previous handler ``` -Developers of web standards understood that long ago and suggested an alternative way of managing handlers using special methods `addEventListener` and `removeEventListener`. They are free of such a problem. +Developers of web standards understood that long ago and suggested an alternative way of managing handlers using the special methods `addEventListener` and `removeEventListener` which do not have the same constraints as event handlers. The syntax to add a handler: From 0c6a4acd94e54f34e078de8856c06b96063c4d30 Mon Sep 17 00:00:00 2001 From: Dave Mackey Date: Tue, 6 Sep 2022 10:33:05 -0400 Subject: [PATCH 07/43] Update article.md Minor grammar changes, clarify that if using a class for `handleEvent` we still are actually using an object as we have to instantiate the class. --- .../2-events/01-introduction-browser-events/article.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/2-ui/2-events/01-introduction-browser-events/article.md b/2-ui/2-events/01-introduction-browser-events/article.md index f75f6c11f..444f49d64 100644 --- a/2-ui/2-events/01-introduction-browser-events/article.md +++ b/2-ui/2-events/01-introduction-browser-events/article.md @@ -261,7 +261,7 @@ input.removeEventListener("click", handler); Please note -- if we don't store the function in a variable, then we can't remove it. There's no way to "read back" handlers assigned by `addEventListener`. ```` -Multiple calls to `addEventListener` allow to add multiple handlers, like this: +Multiple calls to `addEventListener` allow it to add multiple handlers, like this: ```html run no-beautify @@ -288,7 +288,7 @@ As we can see in the example above, we can set handlers *both* using a DOM-prope ````warn header="For some events, handlers only work with `addEventListener`" There exist events that can't be assigned via a DOM-property. Only with `addEventListener`. -For instance, the `DOMContentLoaded` event, that triggers when the document is loaded and DOM is built. +For instance, the `DOMContentLoaded` event, that triggers when the document is loaded and the DOM has been built. ```js // will never run @@ -334,10 +334,10 @@ Some properties of `event` object: `event.currentTarget` : Element that handled the event. That's exactly the same as `this`, unless the handler is an arrow function, or its `this` is bound to something else, then we can get the element from `event.currentTarget`. -`event.clientX / event.clientY` +`event.clientX` / `event.clientY` : Window-relative coordinates of the cursor, for pointer events. -There are more properties. Many of them depend on the event type: keyboard events have one set of properties, pointer events - another one, we'll study them later when we come to different events in details. +There are more properties. Many of them depend on the event type: keyboard events have one set of properties, pointer events - another one, we'll study them later when as we move on to the details of different events. ````smart header="The event object is also available in HTML handlers" If we assign a handler in HTML, we can also use the `event` object, like this: @@ -373,7 +373,7 @@ For instance: As we can see, when `addEventListener` receives an object as the handler, it calls `obj.handleEvent(event)` in case of an event. -We could also use a class for that: +We could also use a class (although we still have to instantiate it as an object): ```html run From 131a3a7d09814565e8e80b5c79270ccbcbc53b47 Mon Sep 17 00:00:00 2001 From: Dave Mackey Date: Tue, 6 Sep 2022 11:03:36 -0400 Subject: [PATCH 08/43] Minor grammar --- 2-ui/2-events/02-bubbling-and-capturing/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/2-ui/2-events/02-bubbling-and-capturing/article.md b/2-ui/2-events/02-bubbling-and-capturing/article.md index 3d55b7d8c..1c85bdb15 100644 --- a/2-ui/2-events/02-bubbling-and-capturing/article.md +++ b/2-ui/2-events/02-bubbling-and-capturing/article.md @@ -192,7 +192,7 @@ There's a property `event.eventPhase` that tells us the number of the phase on w If we `addEventListener(..., true)`, then we should mention the same phase in `removeEventListener(..., true)` to correctly remove the handler. ``` -````smart header="Listeners on same element and same phase run in their set order" +````smart header="Listeners on the same element and same phase run in their set order" If we have multiple event handlers on the same phase, assigned to the same element with `addEventListener`, they run in the same order as they are created: ```js From 11eef4c69a76d6f8c2ce6e0ee04a83ae54dcf792 Mon Sep 17 00:00:00 2001 From: Lavrentiy Rubtsov Date: Wed, 7 Sep 2022 01:42:51 +0600 Subject: [PATCH 09/43] =?UTF-8?q?=F0=9F=91=BE=20add=20mdn=20links=20to=20M?= =?UTF-8?q?ap=20and=20Set=20methods?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 1-js/05-data-types/07-map-set/article.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/1-js/05-data-types/07-map-set/article.md b/1-js/05-data-types/07-map-set/article.md index bd6cad562..2fb2f1080 100644 --- a/1-js/05-data-types/07-map-set/article.md +++ b/1-js/05-data-types/07-map-set/article.md @@ -15,12 +15,12 @@ But that's not enough for real life. That's why `Map` and `Set` also exist. Methods and properties are: - `new Map()` -- creates the map. -- `map.set(key, value)` -- stores the value by the key. -- `map.get(key)` -- returns the value by the key, `undefined` if `key` doesn't exist in map. -- `map.has(key)` -- returns `true` if the `key` exists, `false` otherwise. -- `map.delete(key)` -- removes the value by the key. -- `map.clear()` -- removes everything from the map. -- `map.size` -- returns the current element count. +- [`map.set(key, value)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/set) -- stores the value by the key. +- [`map.get(key)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/get) -- returns the value by the key, `undefined` if `key` doesn't exist in map. +- [`map.has(key)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/has) -- returns `true` if the `key` exists, `false` otherwise. +- [`map.delete(key)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/delete) -- removes the value by the key. +- [`map.clear()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/clear) -- removes everything from the map. +- [`map.size`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/size) -- returns the current element count. For instance: @@ -105,9 +105,9 @@ map.set('1', 'str1') For looping over a `map`, there are 3 methods: -- `map.keys()` -- returns an iterable for keys, -- `map.values()` -- returns an iterable for values, -- `map.entries()` -- returns an iterable for entries `[key, value]`, it's used by default in `for..of`. +- [`map.keys()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/keys) -- returns an iterable for keys, +- [`map.values()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/values) -- returns an iterable for values, +- [`map.entries()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/entries) -- returns an iterable for entries `[key, value]`, it's used by default in `for..of`. For instance: From 82156c44320eed36bd2d21bfa911d605ec5e8fb6 Mon Sep 17 00:00:00 2001 From: Lavrentiy Rubtsov Date: Wed, 7 Sep 2022 02:00:32 +0600 Subject: [PATCH 10/43] =?UTF-8?q?=F0=9F=91=BE=20smth?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 1-js/05-data-types/07-map-set/article.md | 56 ++++++++++++------------ 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/1-js/05-data-types/07-map-set/article.md b/1-js/05-data-types/07-map-set/article.md index 2fb2f1080..a2eedb844 100644 --- a/1-js/05-data-types/07-map-set/article.md +++ b/1-js/05-data-types/07-map-set/article.md @@ -15,12 +15,12 @@ But that's not enough for real life. That's why `Map` and `Set` also exist. Methods and properties are: - `new Map()` -- creates the map. -- [`map.set(key, value)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/set) -- stores the value by the key. -- [`map.get(key)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/get) -- returns the value by the key, `undefined` if `key` doesn't exist in map. -- [`map.has(key)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/has) -- returns `true` if the `key` exists, `false` otherwise. -- [`map.delete(key)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/delete) -- removes the value by the key. -- [`map.clear()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/clear) -- removes everything from the map. -- [`map.size`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/size) -- returns the current element count. +- [`map.set(key, value)`](mdn:js/Map/set) -- stores the value by the key. +- [`map.get(key)`](mdn:js/Map/get) -- returns the value by the key, `undefined` if `key` doesn't exist in map. +- [`map.has(key)`](mdn:js/Map/has) -- returns `true` if the `key` exists, `false` otherwise. +- [`map.delete(key)`](mdn:js/Map/delete) -- removes the value by the key. +- [`map.clear()`](mdn:js/Map/clear) -- removes everything from the map. +- [`map.size`](mdn:js/Map/size) -- returns the current element count. For instance: @@ -105,9 +105,9 @@ map.set('1', 'str1') For looping over a `map`, there are 3 methods: -- [`map.keys()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/keys) -- returns an iterable for keys, -- [`map.values()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/values) -- returns an iterable for values, -- [`map.entries()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/entries) -- returns an iterable for entries `[key, value]`, it's used by default in `for..of`. +- [`map.keys()`](mdn:js/Map/keys) -- returns an iterable for keys, +- [`map.values()`](mdn:js/Map/values) -- returns an iterable for values, +- [`map.entries()`](mdn:js/Map/entries) -- returns an iterable for entries `[key, value]`, it's used by default in `for..of`. For instance: @@ -238,11 +238,11 @@ A `Set` is a special type collection - "set of values" (without keys), where eac Its main methods are: - `new Set(iterable)` -- creates the set, and if an `iterable` object is provided (usually an array), copies values from it into the set. -- `set.add(value)` -- adds a value, returns the set itself. -- `set.delete(value)` -- removes the value, returns `true` if `value` existed at the moment of the call, otherwise `false`. -- `set.has(value)` -- returns `true` if the value exists in the set, otherwise `false`. -- `set.clear()` -- removes everything from the set. -- `set.size` -- is the elements count. +- [`set.add(value)`](mdn:js/Set/add) -- adds a value, returns the set itself. +- [`set.delete(value)`](mdn:js/Set/delete) -- removes the value, returns `true` if `value` existed at the moment of the call, otherwise `false`. +- [`set.has(value)`](mdn:js/Set/has) -- returns `true` if the value exists in the set, otherwise `false`. +- [`set.clear()`](mdn:js/Set/clear) -- removes everything from the set. +- [`set.size`](mdn:js/Set/size) -- is the elements count. The main feature is that repeated calls of `set.add(value)` with the same value don't do anything. That's the reason why each value appears in a `Set` only once. @@ -295,9 +295,9 @@ That's for compatibility with `Map` where the callback passed `forEach` has thre The same methods `Map` has for iterators are also supported: -- `set.keys()` -- returns an iterable object for values, -- `set.values()` -- same as `set.keys()`, for compatibility with `Map`, -- `set.entries()` -- returns an iterable object for entries `[value, value]`, exists for compatibility with `Map`. +- [`set.keys()`](mdn:js/Set/keys) -- returns an iterable object for values, +- [`set.values()`](mdn:js/Set/values) -- same as `set.keys()`, for compatibility with `Map`, +- [`set.entries()`](mdn:js/Set/entries) -- returns an iterable object for entries `[value, value]`, exists for compatibility with `Map`. ## Summary @@ -306,12 +306,12 @@ The same methods `Map` has for iterators are also supported: Methods and properties: - `new Map([iterable])` -- creates the map, with optional `iterable` (e.g. array) of `[key,value]` pairs for initialization. -- `map.set(key, value)` -- stores the value by the key, returns the map itself. -- `map.get(key)` -- returns the value by the key, `undefined` if `key` doesn't exist in map. -- `map.has(key)` -- returns `true` if the `key` exists, `false` otherwise. -- `map.delete(key)` -- removes the value by the key, returns `true` if `key` existed at the moment of the call, otherwise `false`. -- `map.clear()` -- removes everything from the map. -- `map.size` -- returns the current element count. +- [`map.set(key, value)`](mdn:js/Map/set) -- stores the value by the key, returns the map itself. +- [`map.get(key)`](mdn:js/Map/get)` -- returns the value by the key, `undefined` if `key` doesn't exist in map. +- [`map.has(key)`](mdn:js/Map/has) -- returns `true` if the `key` exists, `false` otherwise. +- [`map.delete(key)`](mdn:js/Map/delete) -- removes the value by the key, returns `true` if `key` existed at the moment of the call, otherwise `false`. +- [`map.clear()`](mdn:js/Map/clear) -- removes everything from the map. +- [`map.size`](mdn:js/Map/size) -- returns the current element count. The differences from a regular `Object`: @@ -323,10 +323,10 @@ The differences from a regular `Object`: Methods and properties: - `new Set([iterable])` -- creates the set, with optional `iterable` (e.g. array) of values for initialization. -- `set.add(value)` -- adds a value (does nothing if `value` exists), returns the set itself. -- `set.delete(value)` -- removes the value, returns `true` if `value` existed at the moment of the call, otherwise `false`. -- `set.has(value)` -- returns `true` if the value exists in the set, otherwise `false`. -- `set.clear()` -- removes everything from the set. -- `set.size` -- is the elements count. +- [`set.add(value)`](mdn:js/Set/add) -- adds a value (does nothing if `value` exists), returns the set itself. +- [`set.delete(value)`](mdn:js/Set/delete) -- removes the value, returns `true` if `value` existed at the moment of the call, otherwise `false`. +- [`set.has(value)`](mdn:js/Set/has) -- returns `true` if the value exists in the set, otherwise `false`. +- [`set.clear()`](mdn:js/Set/clear) -- removes everything from the set. +- [`set.size`](mdn:js/Set/size) -- is the elements count. Iteration over `Map` and `Set` is always in the insertion order, so we can't say that these collections are unordered, but we can't reorder elements or directly get an element by its number. From 5f2b5a87130886f59d561f3b8bf3b88c5f4d6931 Mon Sep 17 00:00:00 2001 From: gleachkr Date: Thu, 8 Sep 2022 20:07:53 -0500 Subject: [PATCH 11/43] Update article.md Fix typo --- 1-js/05-data-types/07-map-set/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/05-data-types/07-map-set/article.md b/1-js/05-data-types/07-map-set/article.md index bd6cad562..959ed10d7 100644 --- a/1-js/05-data-types/07-map-set/article.md +++ b/1-js/05-data-types/07-map-set/article.md @@ -291,7 +291,7 @@ set.forEach((value, valueAgain, set) => { Note the funny thing. The callback function passed in `forEach` has 3 arguments: a `value`, then *the same value* `valueAgain`, and then the target object. Indeed, the same value appears in the arguments twice. -That's for compatibility with `Map` where the callback passed `forEach` has three arguments. Looks a bit strange, for sure. But may help to replace `Map` with `Set` in certain cases with ease, and vice versa. +That's for compatibility with `Map` where the callback passed `forEach` has three arguments. Looks a bit strange, for sure. But this convention may help to replace `Map` with `Set` in certain cases with ease, and vice versa. The same methods `Map` has for iterators are also supported: From 4a3e70edbfa859b4a47bd015aadaece078bf0e23 Mon Sep 17 00:00:00 2001 From: Mukul <103566649+mukulkandhari@users.noreply.github.com> Date: Fri, 9 Sep 2022 22:34:16 +0530 Subject: [PATCH 12/43] Update task.md | Fix grammar Replace the value in the middle by "Classics". changed to Replace the value in the middle with "Classics" as the word 'with' describes the situation better --- 1-js/05-data-types/04-array/2-create-array/task.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/05-data-types/04-array/2-create-array/task.md b/1-js/05-data-types/04-array/2-create-array/task.md index 16d14071f..d4551c79c 100644 --- a/1-js/05-data-types/04-array/2-create-array/task.md +++ b/1-js/05-data-types/04-array/2-create-array/task.md @@ -8,7 +8,7 @@ Let's try 5 array operations. 1. Create an array `styles` with items "Jazz" and "Blues". 2. Append "Rock-n-Roll" to the end. -3. Replace the value in the middle by "Classics". Your code for finding the middle value should work for any arrays with odd length. +3. Replace the value in the middle with "Classics". Your code for finding the middle value should work for any arrays with odd length. 4. Strip off the first value of the array and show it. 5. Prepend `Rap` and `Reggae` to the array. From 0f2d22c59502dbc00dc2082f779c653ee4339370 Mon Sep 17 00:00:00 2001 From: Mukul <103566649+mukulkandhari@users.noreply.github.com> Date: Fri, 9 Sep 2022 22:39:37 +0530 Subject: [PATCH 13/43] Update solution.md Fix grammar issues for more clarity --- 1-js/05-data-types/04-array/10-maximal-subarray/solution.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/1-js/05-data-types/04-array/10-maximal-subarray/solution.md b/1-js/05-data-types/04-array/10-maximal-subarray/solution.md index befd80296..7e1ca3bde 100644 --- a/1-js/05-data-types/04-array/10-maximal-subarray/solution.md +++ b/1-js/05-data-types/04-array/10-maximal-subarray/solution.md @@ -59,7 +59,7 @@ alert( getMaxSubSum([100, -9, 2, -3, 5]) ); // 100 The solution has a time complexity of [O(n2)](https://en.wikipedia.org/wiki/Big_O_notation). In other words, if we increase the array size 2 times, the algorithm will work 4 times longer. -For big arrays (1000, 10000 or more items) such algorithms can lead to a serious sluggishness. +For big arrays (1000, 10000 or more items) such algorithms can lead to serious sluggishness. # Fast solution @@ -91,4 +91,4 @@ alert( getMaxSubSum([-1, -2, -3]) ); // 0 The algorithm requires exactly 1 array pass, so the time complexity is O(n). -You can find more detail information about the algorithm here: [Maximum subarray problem](http://en.wikipedia.org/wiki/Maximum_subarray_problem). If it's still not obvious why that works, then please trace the algorithm on the examples above, see how it works, that's better than any words. +You can find more detailed information about the algorithm here: [Maximum subarray problem](http://en.wikipedia.org/wiki/Maximum_subarray_problem). If it's still not obvious why that works, then please trace the algorithm on the examples above, see how it works, that's better than any words. From f15700d02c05f3666cf48c61449f78aed3522932 Mon Sep 17 00:00:00 2001 From: gleachkr Date: Sat, 10 Sep 2022 12:20:12 -0500 Subject: [PATCH 14/43] Update article.md Simplify wording --- 1-js/05-data-types/07-map-set/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/05-data-types/07-map-set/article.md b/1-js/05-data-types/07-map-set/article.md index 959ed10d7..0149fa58c 100644 --- a/1-js/05-data-types/07-map-set/article.md +++ b/1-js/05-data-types/07-map-set/article.md @@ -291,7 +291,7 @@ set.forEach((value, valueAgain, set) => { Note the funny thing. The callback function passed in `forEach` has 3 arguments: a `value`, then *the same value* `valueAgain`, and then the target object. Indeed, the same value appears in the arguments twice. -That's for compatibility with `Map` where the callback passed `forEach` has three arguments. Looks a bit strange, for sure. But this convention may help to replace `Map` with `Set` in certain cases with ease, and vice versa. +That's for compatibility with `Map` where the callback passed `forEach` has three arguments. Looks a bit strange, for sure. But this may help to replace `Map` with `Set` in certain cases with ease, and vice versa. The same methods `Map` has for iterators are also supported: From 026b1c4c86b5431093546a6e2ae6acd0d3cb4050 Mon Sep 17 00:00:00 2001 From: Alexey Chilipenko Date: Thu, 15 Sep 2022 17:48:23 +0300 Subject: [PATCH 15/43] Update String type chapter Update descriptions for Unicode escape sequences. Add minor fixes for different string methods. --- 1-js/05-data-types/03-string/article.md | 31 +++++++++++++++---------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/1-js/05-data-types/03-string/article.md b/1-js/05-data-types/03-string/article.md index 255eb29a7..6df6f005c 100644 --- a/1-js/05-data-types/03-string/article.md +++ b/1-js/05-data-types/03-string/article.md @@ -86,14 +86,14 @@ Here's the full list: |`\\`|Backslash| |`\t`|Tab| |`\b`, `\f`, `\v`| Backspace, Form Feed, Vertical Tab -- kept for compatibility, not used nowadays. | -|`\xXX`|Unicode character with the given hexadecimal Unicode `XX`, e.g. `'\x7A'` is the same as `'z'`.| -|`\uXXXX`|A Unicode symbol with the hex code `XXXX` in UTF-16 encoding, for instance `\u00A9` -- is a Unicode for the copyright symbol `©`. It must be exactly 4 hex digits. | -|`\u{X…XXXXXX}` (1 to 6 hex characters)|A Unicode symbol with the given UTF-32 encoding. Some rare characters are encoded with two Unicode symbols, taking 4 bytes. This way we can insert long codes. | +|`\xXX`|A character whose [Unicode](https://en.wikipedia.org/wiki/Unicode) code point is `U+00XX`. `XX` is always two hexadecimal digits with value between `00` and `FF`, so `\xXX` notation can be used only for the first 256 Unicode characters (including all 128 ASCII characters). For example, `"\x7A"` is the same as `"z"` (Unicode code point `U+007A`).| +|`\uXXXX`|A character whose Unicode code point is `U+XXXX` (a character with the hex code `XXXX` in UTF-16 encoding). `XXXX` must be exactly 4 hex digits with the value between `0000` and `FFFF`, so `\uXXXX` notation can be used for the first 65536 Unicode characters. Characters with Unicode value greater than `U+FFFF` can also be represented with this notation, but in this case we will need to use a so called surrogate pair (we will talk about surrogate pairs later in this chapter). For instance, `"\u00A9"` is a copyright symbol `©` (Unicode code point `U+00A9`), but for smiling cat face 😺 we have to use a surrogate pair `"\uD83D\uDE3A"` (because its Unicode code point `U+1F63A` is greater than `U+FFFF`).| +|`\u{X…XXXXXX}` (1 to 6 hex characters)|A character with any given Unicode code point (a character with the given hex code in UTF-32 encoding). `X…XXXXXX` is a hex value between `0` and `10FFFF` (the highest code point defined by Unicode). This notation was added to the language in ECMAScript 2015 (ES6) standard and allows us to easily represent all existing Unicode characters without need for surrogate pairs. Unlike previous two notations, there is no need to add leading zeros for characters with "small" code point values: `"\u{7A}"`, `"\u{007A}"` and `"\u{00007A}"` are all acceptable.| Examples with Unicode: ```js run -alert( "\u00A9" ); // © +alert( "\u00A9" ); // ©, we will get the very same result with alert( "\xA9" ) and alert( "\u{A9}" ) alert( "\u{20331}" ); // 佫, a rare Chinese hieroglyph (long Unicode) alert( "\u{1F60D}" ); // 😍, a smiling face symbol (another long Unicode) ``` @@ -407,9 +407,9 @@ There are 3 methods in JavaScript to get a substring: `substring`, `substr` and ``` `str.substring(start [, end])` -: Returns the part of the string *between* `start` and `end`. +: Returns the part of the string *between* `start` and `end` (not including the greater of them). - This is almost the same as `slice`, but it allows `start` to be greater than `end`. + This is almost the same as `slice`, but it allows `start` to be greater than `end` (in this case it simply swaps `start` and `end` values). For instance: @@ -452,7 +452,7 @@ Let's recap these methods to avoid any confusion: | method | selects... | negatives | |--------|-----------|-----------| | `slice(start, end)` | from `start` to `end` (not including `end`) | allows negatives | -| `substring(start, end)` | between `start` and `end` | negative values mean `0` | +| `substring(start, end)` | between `start` and `end` (not including the greater of them)| negative values mean `0` | | `substr(start, length)` | from `start` get `length` characters | allows negative `start` | ```smart header="Which one to choose?" @@ -486,12 +486,13 @@ To understand what happens, let's review the internal representation of strings All strings are encoded using [UTF-16](https://en.wikipedia.org/wiki/UTF-16). That is: each character has a corresponding numeric code. There are special methods that allow to get the character for the code and back. `str.codePointAt(pos)` -: Returns the code for the character at position `pos`: +: Returns a decimal number representing the code for the character at position `pos`: ```js run // different case letters have different codes - alert( "z".codePointAt(0) ); // 122 alert( "Z".codePointAt(0) ); // 90 + alert( "z".codePointAt(0) ); // 122 + alert( "z".codePointAt(0).toString(16) ); // 7a (if we need a more commonly used hex value of the code) ``` `String.fromCodePoint(code)` @@ -499,6 +500,7 @@ All strings are encoded using [UTF-16](https://en.wikipedia.org/wiki/UTF-16). Th ```js run alert( String.fromCodePoint(90) ); // Z + alert( String.fromCodePoint(0x5a) ); // Z (we can also use a hex value as an argument) ``` We can also add Unicode characters by their codes using `\u` followed by the hex code: @@ -600,6 +602,11 @@ In the case above: alert( '𝒳'.charCodeAt(0).toString(16) ); // d835, between 0xd800 and 0xdbff alert( '𝒳'.charCodeAt(1).toString(16) ); // dcb3, between 0xdc00 and 0xdfff + +// codePointAt is surrogate-pair aware, but with its own specificity + +alert( '𝒳'.codePointAt(0).toString(16) ); // 1d4b3, reads both parts of the surrogate pair and returns the correct code for the symbol 𝒳 +alert( '𝒳'.codePointAt(1).toString(16) ); // dcb3, returns only the code for the second part of the surrogate pair ``` You will find more ways to deal with surrogate pairs later in the chapter . There are probably special libraries for that too, but nothing famous enough to suggest here. @@ -608,9 +615,9 @@ You will find more ways to deal with surrogate pairs later in the chapter Date: Tue, 20 Sep 2022 13:52:15 +0200 Subject: [PATCH 16/43] closes #3168 --- .../04-variables/3-uppercast-constant/task.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/1-js/02-first-steps/04-variables/3-uppercast-constant/task.md b/1-js/02-first-steps/04-variables/3-uppercast-constant/task.md index 5fd18f90a..f3c208a74 100644 --- a/1-js/02-first-steps/04-variables/3-uppercast-constant/task.md +++ b/1-js/02-first-steps/04-variables/3-uppercast-constant/task.md @@ -12,13 +12,14 @@ const birthday = '18.04.1982'; const age = someCode(birthday); ``` -Here we have a constant `birthday` date and the `age` is calculated from `birthday` with the help of some code (it is not provided for shortness, and because details don't matter here). +Here we have a constant `birthday` for the date, and also the `age` constant. + +The `age` is calculated from `birthday` using `someCode()`, which means a function call that we didn't explain yet (we will soon!), but the details don't matter here, the point is that `age` is calculated somehow based on the `birthday`. Would it be right to use upper case for `birthday`? For `age`? Or even for both? ```js -const BIRTHDAY = '18.04.1982'; // make uppercase? +const BIRTHDAY = '18.04.1982'; // make birthday uppercase? -const AGE = someCode(BIRTHDAY); // make uppercase? +const AGE = someCode(BIRTHDAY); // make age uppercase? ``` - From b0a86b9010d0924c04e0742f2742b7fcecb3e61b Mon Sep 17 00:00:00 2001 From: Ilya Kantor Date: Tue, 20 Sep 2022 13:56:05 +0200 Subject: [PATCH 17/43] minor fixes --- 2-ui/2-events/01-introduction-browser-events/article.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/2-ui/2-events/01-introduction-browser-events/article.md b/2-ui/2-events/01-introduction-browser-events/article.md index e2229d189..0770b73db 100644 --- a/2-ui/2-events/01-introduction-browser-events/article.md +++ b/2-ui/2-events/01-introduction-browser-events/article.md @@ -373,7 +373,7 @@ For instance: As we can see, when `addEventListener` receives an object as the handler, it calls `obj.handleEvent(event)` in case of an event. -We could also use a class (although we still have to instantiate it as an object): +We could also use objects of a custom class, like this: ```html run @@ -395,6 +395,7 @@ We could also use a class (although we still have to instantiate it as an object *!* let menu = new Menu(); + elem.addEventListener('mousedown', menu); elem.addEventListener('mouseup', menu); */!* From 44dc8eb846d7b6b3044fcadfcb792dbbd4d85fa6 Mon Sep 17 00:00:00 2001 From: tianheg Date: Wed, 21 Sep 2022 10:15:47 +0800 Subject: [PATCH 18/43] fix markdown syntax --- 1-js/99-js-misc/04-reference-type/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/99-js-misc/04-reference-type/article.md b/1-js/99-js-misc/04-reference-type/article.md index 6861837a9..894db8fc6 100644 --- a/1-js/99-js-misc/04-reference-type/article.md +++ b/1-js/99-js-misc/04-reference-type/article.md @@ -87,7 +87,7 @@ The result of a property access `user.hi` is not a function, but a value of Refe (user, "hi", true) ``` -When parentheses `()` are called on the Reference Type, they receive the full information about the object and its method, and can set the right `this` (`=user` in this case). +When parentheses `()` are called on the Reference Type, they receive the full information about the object and its method, and can set the right `this` (`user` in this case). Reference type is a special "intermediary" internal type, with the purpose to pass information from dot `.` to calling parentheses `()`. From c2342c1290bf8e068050c8549ff374093e4819c5 Mon Sep 17 00:00:00 2001 From: Ilya Kantor Date: Wed, 21 Sep 2022 16:54:14 +0200 Subject: [PATCH 19/43] minor fixes --- 2-ui/2-events/01-introduction-browser-events/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/2-ui/2-events/01-introduction-browser-events/article.md b/2-ui/2-events/01-introduction-browser-events/article.md index 0d809cb92..4eca222aa 100644 --- a/2-ui/2-events/01-introduction-browser-events/article.md +++ b/2-ui/2-events/01-introduction-browser-events/article.md @@ -207,7 +207,7 @@ input.onclick = function() { alert(1); } input.onclick = function() { alert(2); } // replaces the previous handler ``` -Developers of web standards understood that long ago and suggested an alternative way of managing handlers using the special methods `addEventListener` and `removeEventListener` which do not have the same constraints as event handlers. +Developers of web standards understood that long ago and suggested an alternative way of managing handlers using the special methods `addEventListener` and `removeEventListener` which aren't bound by such constraint. The syntax to add a handler: From f5511ee714a25b26618ef6ab1932658e6c65e2da Mon Sep 17 00:00:00 2001 From: Ilya Kantor Date: Wed, 21 Sep 2022 22:48:50 +0200 Subject: [PATCH 20/43] minor fixes --- 1-js/05-data-types/03-string/article.md | 178 ++++++++++++------------ 1 file changed, 91 insertions(+), 87 deletions(-) diff --git a/1-js/05-data-types/03-string/article.md b/1-js/05-data-types/03-string/article.md index 6df6f005c..9cbf78778 100644 --- a/1-js/05-data-types/03-string/article.md +++ b/1-js/05-data-types/03-string/article.md @@ -59,10 +59,10 @@ It is still possible to create multiline strings with single and double quotes b ```js run let guestList = "Guests:\n * John\n * Pete\n * Mary"; -alert(guestList); // a multiline list of guests +alert(guestList); // a multiline list of guests, same as above ``` -For example, these two lines are equal, just written differently: +As a simpler example, these two lines are equal, just written differently: ```js run let str1 = "Hello\nWorld"; // two lines using a "newline symbol" @@ -74,33 +74,26 @@ World`; alert(str1 == str2); // true ``` -There are other, less common "special" characters. - -Here's the full list: +There are other, less common "special" characters: | Character | Description | |-----------|-------------| |`\n`|New line| |`\r`|In Windows text files a combination of two characters `\r\n` represents a new break, while on non-Windows OS it's just `\n`. That's for historical reasons, most Windows software also understands `\n`. | -|`\'`, `\"`|Quotes| +|`\'`, `\"`, \\`|Quotes| |`\\`|Backslash| |`\t`|Tab| -|`\b`, `\f`, `\v`| Backspace, Form Feed, Vertical Tab -- kept for compatibility, not used nowadays. | -|`\xXX`|A character whose [Unicode](https://en.wikipedia.org/wiki/Unicode) code point is `U+00XX`. `XX` is always two hexadecimal digits with value between `00` and `FF`, so `\xXX` notation can be used only for the first 256 Unicode characters (including all 128 ASCII characters). For example, `"\x7A"` is the same as `"z"` (Unicode code point `U+007A`).| -|`\uXXXX`|A character whose Unicode code point is `U+XXXX` (a character with the hex code `XXXX` in UTF-16 encoding). `XXXX` must be exactly 4 hex digits with the value between `0000` and `FFFF`, so `\uXXXX` notation can be used for the first 65536 Unicode characters. Characters with Unicode value greater than `U+FFFF` can also be represented with this notation, but in this case we will need to use a so called surrogate pair (we will talk about surrogate pairs later in this chapter). For instance, `"\u00A9"` is a copyright symbol `©` (Unicode code point `U+00A9`), but for smiling cat face 😺 we have to use a surrogate pair `"\uD83D\uDE3A"` (because its Unicode code point `U+1F63A` is greater than `U+FFFF`).| -|`\u{X…XXXXXX}` (1 to 6 hex characters)|A character with any given Unicode code point (a character with the given hex code in UTF-32 encoding). `X…XXXXXX` is a hex value between `0` and `10FFFF` (the highest code point defined by Unicode). This notation was added to the language in ECMAScript 2015 (ES6) standard and allows us to easily represent all existing Unicode characters without need for surrogate pairs. Unlike previous two notations, there is no need to add leading zeros for characters with "small" code point values: `"\u{7A}"`, `"\u{007A}"` and `"\u{00007A}"` are all acceptable.| +|`\b`, `\f`, `\v`| Backspace, Form Feed, Vertical Tab -- mentioned for completeness, coming from old times, not used nowadays (you can forget them right now). | -Examples with Unicode: +As you can see, all special characters start with a backslash character `\`. It is also called an "escape character". + +Because it's so special, if we need to show an actual backslash `\` within the string, we need to double it: ```js run -alert( "\u00A9" ); // ©, we will get the very same result with alert( "\xA9" ) and alert( "\u{A9}" ) -alert( "\u{20331}" ); // 佫, a rare Chinese hieroglyph (long Unicode) -alert( "\u{1F60D}" ); // 😍, a smiling face symbol (another long Unicode) +alert( `The backslash: \\` ); // The backslash: \ ``` -All special characters start with a backslash character `\`. It is also called an "escape character". - -We might also use it if we wanted to insert a quote into the string. +So-called "escaped" quotes `\'`, `\"`, \\` are used to insert a quote into the same-quoted string. For instance: @@ -113,18 +106,10 @@ As you can see, we have to prepend the inner quote by the backslash `\'`, becaus Of course, only the quotes that are the same as the enclosing ones need to be escaped. So, as a more elegant solution, we could switch to double quotes or backticks instead: ```js run -alert( `I'm the Walrus!` ); // I'm the Walrus! +alert( "I'm the Walrus!" ); // I'm the Walrus! ``` -Note that the backslash `\` serves for the correct reading of the string by JavaScript, then disappears. The in-memory string has no `\`. You can clearly see that in `alert` from the examples above. - -But what if we need to show an actual backslash `\` within the string? - -That's possible, but we need to double it like `\\`: - -```js run -alert( `The backslash: \\` ); // The backslash: \ -``` +Besides these special characters, there's also a special notation for Unicode codes `\u…`, we'll cover it a bit later in this chapter. ## String length @@ -310,45 +295,6 @@ if (str.indexOf("Widget") != -1) { } ``` -#### The bitwise NOT trick - -One of the old tricks used here is the [bitwise NOT](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_NOT) `~` operator. It converts the number to a 32-bit integer (removes the decimal part if exists) and then reverses all bits in its binary representation. - -In practice, that means a simple thing: for 32-bit integers `~n` equals `-(n+1)`. - -For instance: - -```js run -alert( ~2 ); // -3, the same as -(2+1) -alert( ~1 ); // -2, the same as -(1+1) -alert( ~0 ); // -1, the same as -(0+1) -*!* -alert( ~-1 ); // 0, the same as -(-1+1) -*/!* -``` - -As we can see, `~n` is zero only if `n == -1` (that's for any 32-bit signed integer `n`). - -So, the test `if ( ~str.indexOf("...") )` is truthy only if the result of `indexOf` is not `-1`. In other words, when there is a match. - -People use it to shorten `indexOf` checks: - -```js run -let str = "Widget"; - -if (~str.indexOf("Widget")) { - alert( 'Found it!' ); // works -} -``` - -It is usually not recommended to use language features in a non-obvious way, but this particular trick is widely used in old code, so we should understand it. - -Just remember: `if (~str.indexOf(...))` reads as "if found". - -To be precise though, as big numbers are truncated to 32 bits by `~` operator, there exist other numbers that give `0`, the smallest is `~4294967295=0`. That makes such check correct only if a string is not that long. - -Right now we can see this trick only in the old code, as modern JavaScript provides `.includes` method (see below). - ### includes, startsWith, endsWith The more modern method [str.includes(substr, pos)](mdn:js/String/includes) returns `true/false` depending on whether `str` contains `substr` within. @@ -407,7 +353,7 @@ There are 3 methods in JavaScript to get a substring: `substring`, `substr` and ``` `str.substring(start [, end])` -: Returns the part of the string *between* `start` and `end` (not including the greater of them). +: Returns the part of the string *between* `start` and `end` (not including `end`). This is almost the same as `slice`, but it allows `start` to be greater than `end` (in this case it simply swaps `start` and `end` values). @@ -452,13 +398,15 @@ Let's recap these methods to avoid any confusion: | method | selects... | negatives | |--------|-----------|-----------| | `slice(start, end)` | from `start` to `end` (not including `end`) | allows negatives | -| `substring(start, end)` | between `start` and `end` (not including the greater of them)| negative values mean `0` | +| `substring(start, end)` | between `start` and `end` (not including `end`)| negative values mean `0` | | `substr(start, length)` | from `start` get `length` characters | allows negative `start` | ```smart header="Which one to choose?" All of them can do the job. Formally, `substr` has a minor drawback: it is described not in the core JavaScript specification, but in Annex B, which covers browser-only features that exist mainly for historical reasons. So, non-browser environments may fail to support it. But in practice it works everywhere. -Of the other two variants, `slice` is a little bit more flexible, it allows negative arguments and shorter to write. So, it's enough to remember solely `slice` of these three methods. +Of the other two variants, `slice` is a little bit more flexible, it allows negative arguments and shorter to write. + +So, for practical use it's enough to remember only `slice`. ``` ## Comparing strings @@ -560,17 +508,50 @@ This method actually has two additional arguments specified in [the documentatio ```warn header="Advanced knowledge" The section goes deeper into string internals. This knowledge will be useful for you if you plan to deal with emoji, rare mathematical or hieroglyphic characters or other rare symbols. +``` + +## Unicode characters + +As we already mentioned, JavaScript strings are based on [Unicode](https://en.wikipedia.org/wiki/Unicode). + +Each character is represented by a byte sequence of 1-4 bytes. + +JavaScript allows us to specify a character by its Unicode value using these three notations: + +- `\xXX` -- a character whose Unicode code point is `U+00XX`. + + `XX` is always two hexadecimal digits with value between `00` and `FF`, so `\xXX` notation can be used only for the first 256 Unicode characters (including all 128 ASCII characters). + + These first 256 characters include latin alphabet, most basic syntax characters and some others. For example, `"\x7A"` is the same as `"z"` (Unicode `U+007A`). +- `\uXXXX` -- a character whose Unicode code point is `U+XXXX` (a character with the hex code `XXXX` in UTF-16 encoding). + + `XXXX` must be exactly 4 hex digits with the value between `0000` and `FFFF`, so `\uXXXX` notation can be used for the first 65536 Unicode characters. Characters with Unicode value greater than `U+FFFF` can also be represented with this notation, but in this case we will need to use a so called surrogate pair (we will talk about surrogate pairs later in this chapter). +- `\u{X…XXXXXX}` -- a character with any given Unicode code point (a character with the given hex code in UTF-32 encoding). + + `X…XXXXXX` must be a hexadimal value of 1 to 6 bytes between `0` and `10FFFF` (the highest code point defined by Unicode). This notation allows us to easily represent all existing Unicode characters. + +Examples with Unicode: + +```js run +alert( "\uA9" ); // ©, the copyright symbol -You can skip the section if you don't plan to support them. +alert( "\u00A9" ); // ©, the same as above, using the 4-digit hex notation +alert( "\u044F" ); // я, the cyrillic alphabet letter +alert( "\u2191" ); // ↑, the arrow up symbol + +alert( "\u{20331}" ); // 佫, a rare Chinese hieroglyph (long Unicode) +alert( "\u{1F60D}" ); // 😍, a smiling face symbol (another long Unicode) ``` ### Surrogate pairs All frequently used characters have 2-byte codes. Letters in most european languages, numbers, and even most hieroglyphs, have a 2-byte representation. -But 2 bytes only allow 65536 combinations and that's not enough for every possible symbol. So rare symbols are encoded with a pair of 2-byte characters called "a surrogate pair". +Initially, JavaScript was based on UTF-16 encoding that only allowed 2 bytes per character. But 2 bytes only allow 65536 combinations and that's not enough for every possible symbol of Unicode. + +So rare symbols that require more than 2 bytes are encoded with a pair of 2-byte characters called "a surrogate pair". -The length of such symbols is `2`: +As a side effect, the length of such symbols is `2`: ```js run alert( '𝒳'.length ); // 2, MATHEMATICAL SCRIPT CAPITAL X @@ -578,44 +559,67 @@ alert( '😂'.length ); // 2, FACE WITH TEARS OF JOY alert( '𩷶'.length ); // 2, a rare Chinese hieroglyph ``` -Note that surrogate pairs did not exist at the time when JavaScript was created, and thus are not correctly processed by the language! +That's because surrogate pairs did not exist at the time when JavaScript was created, and thus are not correctly processed by the language! -We actually have a single symbol in each of the strings above, but the `length` shows a length of `2`. +We actually have a single symbol in each of the strings above, but the `length` property shows a length of `2`. -`String.fromCodePoint` and `str.codePointAt` are few rare methods that deal with surrogate pairs right. They recently appeared in the language. Before them, there were only [String.fromCharCode](mdn:js/String/fromCharCode) and [str.charCodeAt](mdn:js/String/charCodeAt). These methods are actually the same as `fromCodePoint/codePointAt`, but don't work with surrogate pairs. +Getting a symbol can also be tricky, because most language features treat surrogate pairs as two characters. -Getting a symbol can be tricky, because surrogate pairs are treated as two characters: +For example, here we can see two odd characters in the output: ```js run -alert( '𝒳'[0] ); // strange symbols... +alert( '𝒳'[0] ); // shows strange symbols... alert( '𝒳'[1] ); // ...pieces of the surrogate pair ``` -Note that pieces of the surrogate pair have no meaning without each other. So the alerts in the example above actually display garbage. +Pieces of a surrogate pair have no meaning without each other. So the alerts in the example above actually display garbage. Technically, surrogate pairs are also detectable by their codes: if a character has the code in the interval of `0xd800..0xdbff`, then it is the first part of the surrogate pair. The next character (second part) must have the code in interval `0xdc00..0xdfff`. These intervals are reserved exclusively for surrogate pairs by the standard. -In the case above: +So the methods `String.fromCodePoint` and `str.codePointAt` were added in JavaScript to deal with surrogate pairs. + +They are essentially the same as [String.fromCharCode](mdn:js/String/fromCharCode) and [str.charCodeAt](mdn:js/String/charCodeAt), but they treat surrogate pairs correctly. + +One can see the difference here: ```js run -// charCodeAt is not surrogate-pair aware, so it gives codes for parts +// charCodeAt is not surrogate-pair aware, so it gives codes for the 1st part of 𝒳: -alert( '𝒳'.charCodeAt(0).toString(16) ); // d835, between 0xd800 and 0xdbff -alert( '𝒳'.charCodeAt(1).toString(16) ); // dcb3, between 0xdc00 and 0xdfff +alert( '𝒳'.charCodeAt(0).toString(16) ); // d835 + +// codePointAt is surrogate-pair aware +alert( '𝒳'.codePointAt(0).toString(16) ); // 1d4b3, reads both parts of the surrogate pair +``` -// codePointAt is surrogate-pair aware, but with its own specificity +That said, if we take from position 1 (and that's rather incorrect here), then they both return only the 2nd part of the pair: -alert( '𝒳'.codePointAt(0).toString(16) ); // 1d4b3, reads both parts of the surrogate pair and returns the correct code for the symbol 𝒳 -alert( '𝒳'.codePointAt(1).toString(16) ); // dcb3, returns only the code for the second part of the surrogate pair +```js run +alert( '𝒳'.charCodeAt(1).toString(16) ); // dcb3 +alert( '𝒳'.codePointAt(1).toString(16) ); // dcb3 +// meaningless 2nd half of the pair ``` You will find more ways to deal with surrogate pairs later in the chapter . There are probably special libraries for that too, but nothing famous enough to suggest here. +````warn header="Takeaway: splitting strings at an arbitrary point is dangerous" +We can't just split a string at an arbitrary position, e.g. take `str.slice(0, 4)` and expect it to be a valid string, e.g.: + +```js run +alert( 'hi 😂'.slice(0, 4) ); // hi [?] +``` + +Here we can see a garbage character (first half of the smile surrogate pair) in the output. + +Just be aware of it if you intend to reliably work with surrogate pairs. May not be a big problem, but at least you should understand what happens. +```` + ### Diacritical marks and normalization In many languages, there are symbols that are composed of the base character with a mark above/under it. -For instance, the letter `a` can be the base character for: `àáâäãåā`. Most common "composite" character have their own code in the Unicode table. But not all of them, because there are too many possible combinations. +For instance, the letter `a` can be the base character for these characters: `àáâäãåā`. + +Most common "composite" characters have their own code in the Unicode table. But not all of them, because there are too many possible combinations. To support arbitrary compositions, Unicode standard allows us to use several Unicode characters: the base character followed by one or many "mark" characters that "decorate" it. @@ -671,7 +675,7 @@ If you want to learn more about normalization rules and variants -- they are des ## Summary - There are 3 types of quotes. Backticks allow a string to span multiple lines and embed expressions `${…}`. -- Strings in JavaScript are encoded using UTF-16. +- Strings in JavaScript are encoded using UTF-16, with surrogate pairs for rare characters (and these cause glitches). - We can use special characters like `\n` and insert letters by their Unicode using `\u...`. - To get a character, use: `[]`. - To get a substring, use: `slice` or `substring`. From 712f47e81d870cc0fe6c6e9776b5828ea5ff6919 Mon Sep 17 00:00:00 2001 From: Ilya Kantor Date: Wed, 21 Sep 2022 22:49:56 +0200 Subject: [PATCH 21/43] minor fixes --- 1-js/05-data-types/03-string/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/05-data-types/03-string/article.md b/1-js/05-data-types/03-string/article.md index 9cbf78778..112285946 100644 --- a/1-js/05-data-types/03-string/article.md +++ b/1-js/05-data-types/03-string/article.md @@ -516,7 +516,7 @@ As we already mentioned, JavaScript strings are based on [Unicode](https://en.wi Each character is represented by a byte sequence of 1-4 bytes. -JavaScript allows us to specify a character by its Unicode value using these three notations: +JavaScript allows us to specify a character not only by directly including it into a stirng, but also by its hexadimal Unicode code using these three notations: - `\xXX` -- a character whose Unicode code point is `U+00XX`. From e7424d4d3ca15ebded75fe3cdf3df115d698e569 Mon Sep 17 00:00:00 2001 From: joaquinelio Date: Fri, 23 Sep 2022 14:09:46 -0300 Subject: [PATCH 22/43] typo --- 1-js/05-data-types/03-string/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/05-data-types/03-string/article.md b/1-js/05-data-types/03-string/article.md index 112285946..47a96d41c 100644 --- a/1-js/05-data-types/03-string/article.md +++ b/1-js/05-data-types/03-string/article.md @@ -528,7 +528,7 @@ JavaScript allows us to specify a character not only by directly including it in `XXXX` must be exactly 4 hex digits with the value between `0000` and `FFFF`, so `\uXXXX` notation can be used for the first 65536 Unicode characters. Characters with Unicode value greater than `U+FFFF` can also be represented with this notation, but in this case we will need to use a so called surrogate pair (we will talk about surrogate pairs later in this chapter). - `\u{X…XXXXXX}` -- a character with any given Unicode code point (a character with the given hex code in UTF-32 encoding). - `X…XXXXXX` must be a hexadimal value of 1 to 6 bytes between `0` and `10FFFF` (the highest code point defined by Unicode). This notation allows us to easily represent all existing Unicode characters. + `X…XXXXXX` must be a hexadecimal value of 1 to 6 bytes between `0` and `10FFFF` (the highest code point defined by Unicode). This notation allows us to easily represent all existing Unicode characters. Examples with Unicode: From 9e649fb911fb6a6c5befc27d8eb9793e890f0f71 Mon Sep 17 00:00:00 2001 From: digital-bw <113027504+digital-bw@users.noreply.github.com> Date: Sat, 24 Sep 2022 01:25:17 +0600 Subject: [PATCH 23/43] Update task.md Missing '()' invoking a constructor. --- .../06-constructor-new/1-two-functions-one-object/task.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/task.md b/1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/task.md index d80113acc..e932a201a 100644 --- a/1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/task.md +++ b/1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/task.md @@ -10,8 +10,8 @@ Is it possible to create functions `A` and `B` so that `new A() == new B()`? function A() { ... } function B() { ... } -let a = new A; -let b = new B; +let a = new A(); +let b = new B(); alert( a == b ); // true ``` From ff4ef57c8c2fd20f4a6aa9032ad37ddac93aa3c4 Mon Sep 17 00:00:00 2001 From: Ilya Kantor Date: Sat, 24 Sep 2022 13:46:33 +0200 Subject: [PATCH 24/43] minor fixes --- 1-js/05-data-types/03-string/article.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/1-js/05-data-types/03-string/article.md b/1-js/05-data-types/03-string/article.md index 47a96d41c..d55d23b93 100644 --- a/1-js/05-data-types/03-string/article.md +++ b/1-js/05-data-types/03-string/article.md @@ -516,11 +516,11 @@ As we already mentioned, JavaScript strings are based on [Unicode](https://en.wi Each character is represented by a byte sequence of 1-4 bytes. -JavaScript allows us to specify a character not only by directly including it into a stirng, but also by its hexadimal Unicode code using these three notations: +JavaScript allows us to specify a character not only by directly including it into a stirng, but also by its hexadecimal Unicode code using these three notations: - `\xXX` -- a character whose Unicode code point is `U+00XX`. - `XX` is always two hexadecimal digits with value between `00` and `FF`, so `\xXX` notation can be used only for the first 256 Unicode characters (including all 128 ASCII characters). + `XX` is two hexadecimal digits with value between `00` and `FF`, so `\xXX` notation can be used only for the first 256 Unicode characters (including all 128 ASCII characters). These first 256 characters include latin alphabet, most basic syntax characters and some others. For example, `"\x7A"` is the same as `"z"` (Unicode `U+007A`). - `\uXXXX` -- a character whose Unicode code point is `U+XXXX` (a character with the hex code `XXXX` in UTF-16 encoding). From dfb97dc9ebf9576a7083dde024f77e72590a35fc Mon Sep 17 00:00:00 2001 From: digital-bw <113027504+digital-bw@users.noreply.github.com> Date: Sat, 24 Sep 2022 19:00:37 +0600 Subject: [PATCH 25/43] fix a small typo --- 1-js/05-data-types/02-number/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/05-data-types/02-number/article.md b/1-js/05-data-types/02-number/article.md index 8e130f745..18d833376 100644 --- a/1-js/05-data-types/02-number/article.md +++ b/1-js/05-data-types/02-number/article.md @@ -352,7 +352,7 @@ Please note that an empty or a space-only string is treated as `0` in all numeri ```js run alert( Number.isFinite(123) ); // true - alert( Number.isFinite(Infinity) ); //false + alert( Number.isFinite(Infinity) ); // false alert( Number.isFinite(2 / 0) ); // false // Note the difference: From a4877dfbb8e2df99c76dc081bf8cd787bd07cc35 Mon Sep 17 00:00:00 2001 From: Dmitrii <42495435+skromez@users.noreply.github.com> Date: Sat, 24 Sep 2022 15:30:31 +0200 Subject: [PATCH 26/43] fix typo I don't see anyone using vice verse with "-" in between, so decided to remove it as well. --- 8-web-components/5-slots-composition/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/8-web-components/5-slots-composition/article.md b/8-web-components/5-slots-composition/article.md index c35824a9e..e6d1eaf00 100644 --- a/8-web-components/5-slots-composition/article.md +++ b/8-web-components/5-slots-composition/article.md @@ -381,7 +381,7 @@ If we'd like to track internal modifications of light DOM from JavaScript, that' Finally, let's mention the slot-related JavaScript methods. -As we've seen before, JavaScript looks at the "real" DOM, without flattening. But, if the shadow tree has `{mode: 'open'}`, then we can figure out which elements assigned to a slot and, vise-versa, the slot by the element inside it: +As we've seen before, JavaScript looks at the "real" DOM, without flattening. But, if the shadow tree has `{mode: 'open'}`, then we can figure out which elements assigned to a slot and, vice versa, the slot by the element inside it: - `node.assignedSlot` -- returns the `` element that the `node` is assigned to. - `slot.assignedNodes({flatten: true/false})` -- DOM nodes, assigned to the slot. The `flatten` option is `false` by default. If explicitly set to `true`, then it looks more deeply into the flattened DOM, returning nested slots in case of nested components and the fallback content if no node assigned. From 1575b8a212f8b1232d9a30e28a9ce915992ae2e8 Mon Sep 17 00:00:00 2001 From: digital-bw <113027504+digital-bw@users.noreply.github.com> Date: Sat, 24 Sep 2022 19:41:33 +0600 Subject: [PATCH 27/43] fix small typo --- 1-js/05-data-types/02-number/2-why-rounded-down/solution.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/05-data-types/02-number/2-why-rounded-down/solution.md b/1-js/05-data-types/02-number/2-why-rounded-down/solution.md index a17a4671a..4bcd74512 100644 --- a/1-js/05-data-types/02-number/2-why-rounded-down/solution.md +++ b/1-js/05-data-types/02-number/2-why-rounded-down/solution.md @@ -28,6 +28,6 @@ Note that `63.5` has no precision loss at all. That's because the decimal part ` ```js run -alert( Math.round(6.35 * 10) / 10); // 6.35 -> 63.5 -> 64(rounded) -> 6.4 +alert( Math.round(6.35 * 10) / 10 ); // 6.35 -> 63.5 -> 64(rounded) -> 6.4 ``` From 86ed165f1b697f3876c57973887d92ccfd7faa17 Mon Sep 17 00:00:00 2001 From: digital-bw <113027504+digital-bw@users.noreply.github.com> Date: Sat, 24 Sep 2022 19:50:06 +0600 Subject: [PATCH 28/43] grammar suggestion contextually 'true' can be confusing after 'false' in sentence: "... false, technically that's true ..." --- 1-js/05-data-types/02-number/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/05-data-types/02-number/article.md b/1-js/05-data-types/02-number/article.md index 8e130f745..0f0ee2bf6 100644 --- a/1-js/05-data-types/02-number/article.md +++ b/1-js/05-data-types/02-number/article.md @@ -367,7 +367,7 @@ In a way, `Number.isNaN` and `Number.isFinite` are simpler and more straightforw There is a special built-in method `Object.is` that compares values like `===`, but is more reliable for two edge cases: 1. It works with `NaN`: `Object.is(NaN, NaN) === true`, that's a good thing. -2. Values `0` and `-0` are different: `Object.is(0, -0) === false`, technically that's true, because internally the number has a sign bit that may be different even if all other bits are zeroes. +2. Values `0` and `-0` are different: `Object.is(0, -0) === false`, technically that's correct, because internally the number has a sign bit that may be different even if all other bits are zeroes. In all other cases, `Object.is(a, b)` is the same as `a === b`. From 1b87b89f2bb247dadb25568af14af4db36e61f21 Mon Sep 17 00:00:00 2001 From: Samuel Braun Date: Sun, 25 Sep 2022 14:59:06 +0200 Subject: [PATCH 29/43] Omitting parentheses after `new` Parentheses can be omitted even if the constructor function has arguments: ```js new function(test) { return { test } } // Works the same as new (function(test) { return { test } })(); ``` --- 1-js/04-object-basics/06-constructor-new/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/04-object-basics/06-constructor-new/article.md b/1-js/04-object-basics/06-constructor-new/article.md index f3e9c3ec0..a335464f1 100644 --- a/1-js/04-object-basics/06-constructor-new/article.md +++ b/1-js/04-object-basics/06-constructor-new/article.md @@ -171,7 +171,7 @@ alert( new SmallUser().name ); // John Usually constructors don't have a `return` statement. Here we mention the special behavior with returning objects mainly for the sake of completeness. ````smart header="Omitting parentheses" -By the way, we can omit parentheses after `new`, if it has no arguments: +By the way, we can omit parentheses after `new`: ```js let user = new User; // <-- no parentheses From a965e49ad830da1c90069c8bba9f95ece0f19393 Mon Sep 17 00:00:00 2001 From: joaquinelio Date: Tue, 27 Sep 2022 00:04:49 -0300 Subject: [PATCH 30/43] typo --- 1-js/05-data-types/07-map-set/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/05-data-types/07-map-set/article.md b/1-js/05-data-types/07-map-set/article.md index d7cfe46a3..354070888 100644 --- a/1-js/05-data-types/07-map-set/article.md +++ b/1-js/05-data-types/07-map-set/article.md @@ -307,7 +307,7 @@ Methods and properties: - `new Map([iterable])` -- creates the map, with optional `iterable` (e.g. array) of `[key,value]` pairs for initialization. - [`map.set(key, value)`](mdn:js/Map/set) -- stores the value by the key, returns the map itself. -- [`map.get(key)`](mdn:js/Map/get)` -- returns the value by the key, `undefined` if `key` doesn't exist in map. +- [`map.get(key)`](mdn:js/Map/get) -- returns the value by the key, `undefined` if `key` doesn't exist in map. - [`map.has(key)`](mdn:js/Map/has) -- returns `true` if the `key` exists, `false` otherwise. - [`map.delete(key)`](mdn:js/Map/delete) -- removes the value by the key, returns `true` if `key` existed at the moment of the call, otherwise `false`. - [`map.clear()`](mdn:js/Map/clear) -- removes everything from the map. From 4c693a22c578b5ad57c09b75f8282ed46f6c213f Mon Sep 17 00:00:00 2001 From: Dmitrii <42495435+skromez@users.noreply.github.com> Date: Tue, 27 Sep 2022 12:02:02 +0200 Subject: [PATCH 31/43] Update article.md --- 8-web-components/5-slots-composition/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/8-web-components/5-slots-composition/article.md b/8-web-components/5-slots-composition/article.md index e6d1eaf00..c41e26e05 100644 --- a/8-web-components/5-slots-composition/article.md +++ b/8-web-components/5-slots-composition/article.md @@ -381,7 +381,7 @@ If we'd like to track internal modifications of light DOM from JavaScript, that' Finally, let's mention the slot-related JavaScript methods. -As we've seen before, JavaScript looks at the "real" DOM, without flattening. But, if the shadow tree has `{mode: 'open'}`, then we can figure out which elements assigned to a slot and, vice versa, the slot by the element inside it: +As we've seen before, JavaScript looks at the "real" DOM, without flattening. But, if the shadow tree has `{mode: 'open'}`, then we can figure out which elements assigned to a slot and, vice-versa, the slot by the element inside it: - `node.assignedSlot` -- returns the `` element that the `node` is assigned to. - `slot.assignedNodes({flatten: true/false})` -- DOM nodes, assigned to the slot. The `flatten` option is `false` by default. If explicitly set to `true`, then it looks more deeply into the flattened DOM, returning nested slots in case of nested components and the fallback content if no node assigned. From 1292386071116491bd7383fea1d930a1f8240c7b Mon Sep 17 00:00:00 2001 From: joaquinelio Date: Wed, 28 Sep 2022 10:03:49 -0300 Subject: [PATCH 32/43] typo --- 1-js/05-data-types/03-string/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/05-data-types/03-string/article.md b/1-js/05-data-types/03-string/article.md index d55d23b93..df86ffff5 100644 --- a/1-js/05-data-types/03-string/article.md +++ b/1-js/05-data-types/03-string/article.md @@ -516,7 +516,7 @@ As we already mentioned, JavaScript strings are based on [Unicode](https://en.wi Each character is represented by a byte sequence of 1-4 bytes. -JavaScript allows us to specify a character not only by directly including it into a stirng, but also by its hexadecimal Unicode code using these three notations: +JavaScript allows us to specify a character not only by directly including it into a string, but also by its hexadecimal Unicode code using these three notations: - `\xXX` -- a character whose Unicode code point is `U+00XX`. From fe525d2c9356177d71febc3a356784f2016879ea Mon Sep 17 00:00:00 2001 From: romanstetsyk <25715951+romanstetsyk@users.noreply.github.com> Date: Wed, 28 Sep 2022 16:11:14 +0100 Subject: [PATCH 33/43] Change link to the spec --- .../08-settimeout-setinterval/article.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/1-js/06-advanced-functions/08-settimeout-setinterval/article.md b/1-js/06-advanced-functions/08-settimeout-setinterval/article.md index fa1d98cb9..5a40238b1 100644 --- a/1-js/06-advanced-functions/08-settimeout-setinterval/article.md +++ b/1-js/06-advanced-functions/08-settimeout-setinterval/article.md @@ -102,7 +102,7 @@ As we can see from `alert` output, in a browser the timer identifier is a number Again, there is no universal specification for these methods, so that's fine. -For browsers, timers are described in the [timers section](https://www.w3.org/TR/html5/webappapis.html#timers) of HTML5 standard. +For browsers, timers are described in the [timers section](https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers) of HTML Living Standard. ## setInterval @@ -256,7 +256,7 @@ The first line "puts the call into calendar after 0ms". But the scheduler will o There are also advanced browser-related use cases of zero-delay timeout, that we'll discuss in the chapter . ````smart header="Zero delay is in fact not zero (in a browser)" -In the browser, there's a limitation of how often nested timers can run. The [HTML5 standard](https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers) says: "after five nested timers, the interval is forced to be at least 4 milliseconds.". +In the browser, there's a limitation of how often nested timers can run. The [HTML Living Standard](https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers) says: "after five nested timers, the interval is forced to be at least 4 milliseconds.". Let's demonstrate what it means with the example below. The `setTimeout` call in it re-schedules itself with zero delay. Each call remembers the real time from the previous one in the `times` array. What do the real delays look like? Let's see: From f2ef231b6eb24d0b8b99c7793b4885f1b0b19e64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ann=20Kilzer=20=E3=82=AD=E3=83=AB=E3=82=B6=E3=83=BC?= =?UTF-8?q?=E6=9D=8F?= Date: Thu, 29 Sep 2022 12:08:59 +0900 Subject: [PATCH 34/43] Fix typo "stirng" to "string" --- 1-js/05-data-types/03-string/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/05-data-types/03-string/article.md b/1-js/05-data-types/03-string/article.md index d55d23b93..df86ffff5 100644 --- a/1-js/05-data-types/03-string/article.md +++ b/1-js/05-data-types/03-string/article.md @@ -516,7 +516,7 @@ As we already mentioned, JavaScript strings are based on [Unicode](https://en.wi Each character is represented by a byte sequence of 1-4 bytes. -JavaScript allows us to specify a character not only by directly including it into a stirng, but also by its hexadecimal Unicode code using these three notations: +JavaScript allows us to specify a character not only by directly including it into a string, but also by its hexadecimal Unicode code using these three notations: - `\xXX` -- a character whose Unicode code point is `U+00XX`. From 8d89b7facdf03b6c513676164d9a15e2f91917bd Mon Sep 17 00:00:00 2001 From: joaquinelio Date: Thu, 29 Sep 2022 10:58:36 -0300 Subject: [PATCH 35/43] ECMA broken link --- 1-js/05-data-types/03-string/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/05-data-types/03-string/article.md b/1-js/05-data-types/03-string/article.md index d55d23b93..2f6cbb01e 100644 --- a/1-js/05-data-types/03-string/article.md +++ b/1-js/05-data-types/03-string/article.md @@ -486,7 +486,7 @@ The "right" algorithm to do string comparisons is more complex than it may seem, So, the browser needs to know the language to compare. -Luckily, all modern browsers (IE10- requires the additional library [Intl.js](https://github.com/andyearnshaw/Intl.js/)) support the internationalization standard [ECMA-402](http://www.ecma-international.org/ecma-402/1.0/ECMA-402.pdf). +Luckily, all modern browsers (IE10- requires the additional library [Intl.js](https://github.com/andyearnshaw/Intl.js/)) support the internationalization standard [ECMA-402](https://www.ecma-international.org/publications-and-standards/standards/ecma-402/). It provides a special method to compare strings in different languages, following their rules. From 24dfb1f30a7d9ed4e0a691cc3e93b329c562b4fa Mon Sep 17 00:00:00 2001 From: Yang Yang Date: Thu, 29 Sep 2022 23:13:45 +0800 Subject: [PATCH 36/43] Remove description of inconsistency between Chrome and Firefox Firefox v105 also shows `10px`. --- 2-ui/1-document/08-styles-and-classes/article.md | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/2-ui/1-document/08-styles-and-classes/article.md b/2-ui/1-document/08-styles-and-classes/article.md index 644583c34..46aaa3b00 100644 --- a/2-ui/1-document/08-styles-and-classes/article.md +++ b/2-ui/1-document/08-styles-and-classes/article.md @@ -269,20 +269,6 @@ So nowadays `getComputedStyle` actually returns the resolved value of the proper We should always ask for the exact property that we want, like `paddingLeft` or `marginTop` or `borderTopWidth`. Otherwise the correct result is not guaranteed. For instance, if there are properties `paddingLeft/paddingTop`, then what should we get for `getComputedStyle(elem).padding`? Nothing, or maybe a "generated" value from known paddings? There's no standard rule here. - -There are other inconsistencies. As an example, some browsers (Chrome) show `10px` in the document below, and some of them (Firefox) -- do not: - -```html run - - -``` ```` ```smart header="Styles applied to `:visited` links are hidden!" From 594bc55841e1e577ca29877c260d578a9caf60af Mon Sep 17 00:00:00 2001 From: joaquinelio Date: Thu, 29 Sep 2022 13:49:40 -0300 Subject: [PATCH 37/43] https link --- 1-js/05-data-types/03-string/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/05-data-types/03-string/article.md b/1-js/05-data-types/03-string/article.md index d55d23b93..abb315fa8 100644 --- a/1-js/05-data-types/03-string/article.md +++ b/1-js/05-data-types/03-string/article.md @@ -670,7 +670,7 @@ alert( "S\u0307\u0323".normalize() == "\u1e68" ); // true In reality, this is not always the case. The reason being that the symbol `Ṩ` is "common enough", so Unicode creators included it in the main table and gave it the code. -If you want to learn more about normalization rules and variants -- they are described in the appendix of the Unicode standard: [Unicode Normalization Forms](http://www.unicode.org/reports/tr15/), but for most practical purposes the information from this section is enough. +If you want to learn more about normalization rules and variants -- they are described in the appendix of the Unicode standard: [Unicode Normalization Forms](https://www.unicode.org/reports/tr15/), but for most practical purposes the information from this section is enough. ## Summary From c8b4d340d38f1d6d26d4eece6acdce797c4d84b2 Mon Sep 17 00:00:00 2001 From: Ilya Kantor Date: Sat, 1 Oct 2022 18:30:25 +0200 Subject: [PATCH 38/43] move Unicode to a separate article --- .../03-string/1-ucfirst/solution.md | 8 +- 1-js/05-data-types/03-string/article.md | 212 ++---------------- 1-js/99-js-misc/06-unicode/article.md | 172 ++++++++++++++ 3 files changed, 194 insertions(+), 198 deletions(-) create mode 100644 1-js/99-js-misc/06-unicode/article.md diff --git a/1-js/05-data-types/03-string/1-ucfirst/solution.md b/1-js/05-data-types/03-string/1-ucfirst/solution.md index f7a332d0d..be5dd2aaf 100644 --- a/1-js/05-data-types/03-string/1-ucfirst/solution.md +++ b/1-js/05-data-types/03-string/1-ucfirst/solution.md @@ -8,12 +8,7 @@ let newStr = str[0].toUpperCase() + str.slice(1); There's a small problem though. If `str` is empty, then `str[0]` is `undefined`, and as `undefined` doesn't have the `toUpperCase()` method, we'll get an error. -There are two variants here: - -1. Use `str.charAt(0)`, as it always returns a string (maybe empty). -2. Add a test for an empty string. - -Here's the 2nd variant: +The easiest way out is to add a test for an empty string, like this: ```js run demo function ucFirst(str) { @@ -24,4 +19,3 @@ function ucFirst(str) { alert( ucFirst("john") ); // John ``` - diff --git a/1-js/05-data-types/03-string/article.md b/1-js/05-data-types/03-string/article.md index e5f7bf1d7..618f8ef3b 100644 --- a/1-js/05-data-types/03-string/article.md +++ b/1-js/05-data-types/03-string/article.md @@ -50,7 +50,7 @@ let guestList = "Guests: // Error: Unexpected token ILLEGAL Single and double quotes come from ancient times of language creation, when the need for multiline strings was not taken into account. Backticks appeared much later and thus are more versatile. -Backticks also allow us to specify a "template function" before the first backtick. The syntax is: func`string`. The function `func` is called automatically, receives the string and embedded expressions and can process them. This is called "tagged templates". This feature makes it easier to implement custom templating, but is rarely used in practice. You can read more about it in the [manual](mdn:/JavaScript/Reference/Template_literals#Tagged_templates). +Backticks also allow us to specify a "template function" before the first backtick. The syntax is: func`string`. The function `func` is called automatically, receives the string and embedded expressions and can process them. This feature is called "tagged templates", it's rarely seen, but you can read about it in the MDN: [Template literals](mdn:/JavaScript/Reference/Template_literals#Tagged_templates). ## Special characters @@ -74,7 +74,7 @@ World`; alert(str1 == str2); // true ``` -There are other, less common "special" characters: +There are other, less common special characters: | Character | Description | |-----------|-------------| @@ -109,7 +109,7 @@ Of course, only the quotes that are the same as the enclosing ones need to be es alert( "I'm the Walrus!" ); // I'm the Walrus! ``` -Besides these special characters, there's also a special notation for Unicode codes `\u…`, we'll cover it a bit later in this chapter. +Besides these special characters, there's also a special notation for Unicode codes `\u…`, it's rarely used and is covered in the optional chapter about [Unicode](info:unicode). ## String length @@ -124,33 +124,36 @@ Note that `\n` is a single "special" character, so the length is indeed `3`. ```warn header="`length` is a property" People with a background in some other languages sometimes mistype by calling `str.length()` instead of just `str.length`. That doesn't work. -Please note that `str.length` is a numeric property, not a function. There is no need to add parenthesis after it. +Please note that `str.length` is a numeric property, not a function. There is no need to add parenthesis after it. Not `.length()`, but `.length`. ``` ## Accessing characters -To get a character at position `pos`, use square brackets `[pos]` or call the method [str.charAt(pos)](mdn:js/String/charAt). The first character starts from the zero position: +To get a character at position `pos`, use square brackets `[pos]` or call the method [str.at(pos)](mdn:js/String/at). The first character starts from the zero position: ```js run let str = `Hello`; // the first character alert( str[0] ); // H -alert( str.charAt(0) ); // H +alert( str.at(0) ); // H // the last character alert( str[str.length - 1] ); // o +alert( str.at(-1) ); ``` -The square brackets are a modern way of getting a character, while `charAt` exists mostly for historical reasons. +As you can see, the `.at(pos)` method has a benefit of allowing negative position. If `pos` is negative, then it's counted from the end of the string. -The only difference between them is that if no character is found, `[]` returns `undefined`, and `charAt` returns an empty string: +So `.at(-1)` means the last character, and `.at(-2)` is the one before it, etc. + +The square brackets always return `undefined` for negative indexes, for instance: ```js run let str = `Hello`; -alert( str[1000] ); // undefined -alert( str.charAt(1000) ); // '' (an empty string) +alert( str[-2] ); // undefined +alert( str.at(-2) ); // l ``` We can also iterate over characters using `for..of`: @@ -429,9 +432,9 @@ Although, there are some oddities. This may lead to strange results if we sort these country names. Usually people would expect `Zealand` to come after `Österreich` in the list. -To understand what happens, let's review the internal representation of strings in JavaScript. +To understand what happens, we should be aware that strings in Javascript are encoded using [UTF-16](https://en.wikipedia.org/wiki/UTF-16). That is: each character has a corresponding numeric code. -All strings are encoded using [UTF-16](https://en.wikipedia.org/wiki/UTF-16). That is: each character has a corresponding numeric code. There are special methods that allow to get the character for the code and back. +There are special methods that allow to get the character for the code and back: `str.codePointAt(pos)` : Returns a decimal number representing the code for the character at position `pos`: @@ -440,7 +443,7 @@ All strings are encoded using [UTF-16](https://en.wikipedia.org/wiki/UTF-16). Th // different case letters have different codes alert( "Z".codePointAt(0) ); // 90 alert( "z".codePointAt(0) ); // 122 - alert( "z".codePointAt(0).toString(16) ); // 7a (if we need a more commonly used hex value of the code) + alert( "z".codePointAt(0).toString(16) ); // 7a (if we need a hexadecimal value) ``` `String.fromCodePoint(code)` @@ -451,13 +454,6 @@ All strings are encoded using [UTF-16](https://en.wikipedia.org/wiki/UTF-16). Th alert( String.fromCodePoint(0x5a) ); // Z (we can also use a hex value as an argument) ``` - We can also add Unicode characters by their codes using `\u` followed by the hex code: - - ```js run - // 90 is 5a in hexadecimal system - alert( '\u005a' ); // Z - ``` - Now let's see the characters with codes `65..220` (the latin alphabet and a little bit extra) by making a string of them: ```js run @@ -467,6 +463,7 @@ for (let i = 65; i <= 220; i++) { str += String.fromCodePoint(i); } alert( str ); +// Output: // ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„ // ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜ ``` @@ -486,7 +483,7 @@ The "right" algorithm to do string comparisons is more complex than it may seem, So, the browser needs to know the language to compare. -Luckily, all modern browsers (IE10- requires the additional library [Intl.js](https://github.com/andyearnshaw/Intl.js/)) support the internationalization standard [ECMA-402](https://www.ecma-international.org/publications-and-standards/standards/ecma-402/). +Luckily, modern browsers support the internationalization standard [ECMA-402](https://www.ecma-international.org/publications-and-standards/standards/ecma-402/). It provides a special method to compare strings in different languages, following their rules. @@ -504,179 +501,10 @@ alert( 'Österreich'.localeCompare('Zealand') ); // -1 This method actually has two additional arguments specified in [the documentation](mdn:js/String/localeCompare), which allows it to specify the language (by default taken from the environment, letter order depends on the language) and setup additional rules like case sensitivity or should `"a"` and `"á"` be treated as the same etc. -## Internals, Unicode - -```warn header="Advanced knowledge" -The section goes deeper into string internals. This knowledge will be useful for you if you plan to deal with emoji, rare mathematical or hieroglyphic characters or other rare symbols. -``` - -## Unicode characters - -As we already mentioned, JavaScript strings are based on [Unicode](https://en.wikipedia.org/wiki/Unicode). - -Each character is represented by a byte sequence of 1-4 bytes. - -JavaScript allows us to specify a character not only by directly including it into a string, but also by its hexadecimal Unicode code using these three notations: - -- `\xXX` -- a character whose Unicode code point is `U+00XX`. - - `XX` is two hexadecimal digits with value between `00` and `FF`, so `\xXX` notation can be used only for the first 256 Unicode characters (including all 128 ASCII characters). - - These first 256 characters include latin alphabet, most basic syntax characters and some others. For example, `"\x7A"` is the same as `"z"` (Unicode `U+007A`). -- `\uXXXX` -- a character whose Unicode code point is `U+XXXX` (a character with the hex code `XXXX` in UTF-16 encoding). - - `XXXX` must be exactly 4 hex digits with the value between `0000` and `FFFF`, so `\uXXXX` notation can be used for the first 65536 Unicode characters. Characters with Unicode value greater than `U+FFFF` can also be represented with this notation, but in this case we will need to use a so called surrogate pair (we will talk about surrogate pairs later in this chapter). -- `\u{X…XXXXXX}` -- a character with any given Unicode code point (a character with the given hex code in UTF-32 encoding). - - `X…XXXXXX` must be a hexadecimal value of 1 to 6 bytes between `0` and `10FFFF` (the highest code point defined by Unicode). This notation allows us to easily represent all existing Unicode characters. - -Examples with Unicode: - -```js run -alert( "\uA9" ); // ©, the copyright symbol - -alert( "\u00A9" ); // ©, the same as above, using the 4-digit hex notation -alert( "\u044F" ); // я, the cyrillic alphabet letter -alert( "\u2191" ); // ↑, the arrow up symbol - -alert( "\u{20331}" ); // 佫, a rare Chinese hieroglyph (long Unicode) -alert( "\u{1F60D}" ); // 😍, a smiling face symbol (another long Unicode) -``` - -### Surrogate pairs - -All frequently used characters have 2-byte codes. Letters in most european languages, numbers, and even most hieroglyphs, have a 2-byte representation. - -Initially, JavaScript was based on UTF-16 encoding that only allowed 2 bytes per character. But 2 bytes only allow 65536 combinations and that's not enough for every possible symbol of Unicode. - -So rare symbols that require more than 2 bytes are encoded with a pair of 2-byte characters called "a surrogate pair". - -As a side effect, the length of such symbols is `2`: - -```js run -alert( '𝒳'.length ); // 2, MATHEMATICAL SCRIPT CAPITAL X -alert( '😂'.length ); // 2, FACE WITH TEARS OF JOY -alert( '𩷶'.length ); // 2, a rare Chinese hieroglyph -``` - -That's because surrogate pairs did not exist at the time when JavaScript was created, and thus are not correctly processed by the language! - -We actually have a single symbol in each of the strings above, but the `length` property shows a length of `2`. - -Getting a symbol can also be tricky, because most language features treat surrogate pairs as two characters. - -For example, here we can see two odd characters in the output: - -```js run -alert( '𝒳'[0] ); // shows strange symbols... -alert( '𝒳'[1] ); // ...pieces of the surrogate pair -``` - -Pieces of a surrogate pair have no meaning without each other. So the alerts in the example above actually display garbage. - -Technically, surrogate pairs are also detectable by their codes: if a character has the code in the interval of `0xd800..0xdbff`, then it is the first part of the surrogate pair. The next character (second part) must have the code in interval `0xdc00..0xdfff`. These intervals are reserved exclusively for surrogate pairs by the standard. - -So the methods `String.fromCodePoint` and `str.codePointAt` were added in JavaScript to deal with surrogate pairs. - -They are essentially the same as [String.fromCharCode](mdn:js/String/fromCharCode) and [str.charCodeAt](mdn:js/String/charCodeAt), but they treat surrogate pairs correctly. - -One can see the difference here: - -```js run -// charCodeAt is not surrogate-pair aware, so it gives codes for the 1st part of 𝒳: - -alert( '𝒳'.charCodeAt(0).toString(16) ); // d835 - -// codePointAt is surrogate-pair aware -alert( '𝒳'.codePointAt(0).toString(16) ); // 1d4b3, reads both parts of the surrogate pair -``` - -That said, if we take from position 1 (and that's rather incorrect here), then they both return only the 2nd part of the pair: - -```js run -alert( '𝒳'.charCodeAt(1).toString(16) ); // dcb3 -alert( '𝒳'.codePointAt(1).toString(16) ); // dcb3 -// meaningless 2nd half of the pair -``` - -You will find more ways to deal with surrogate pairs later in the chapter . There are probably special libraries for that too, but nothing famous enough to suggest here. - -````warn header="Takeaway: splitting strings at an arbitrary point is dangerous" -We can't just split a string at an arbitrary position, e.g. take `str.slice(0, 4)` and expect it to be a valid string, e.g.: - -```js run -alert( 'hi 😂'.slice(0, 4) ); // hi [?] -``` - -Here we can see a garbage character (first half of the smile surrogate pair) in the output. - -Just be aware of it if you intend to reliably work with surrogate pairs. May not be a big problem, but at least you should understand what happens. -```` - -### Diacritical marks and normalization - -In many languages, there are symbols that are composed of the base character with a mark above/under it. - -For instance, the letter `a` can be the base character for these characters: `àáâäãåā`. - -Most common "composite" characters have their own code in the Unicode table. But not all of them, because there are too many possible combinations. - -To support arbitrary compositions, Unicode standard allows us to use several Unicode characters: the base character followed by one or many "mark" characters that "decorate" it. - -For instance, if we have `S` followed by the special "dot above" character (code `\u0307`), it is shown as Ṡ. - -```js run -alert( 'S\u0307' ); // Ṡ -``` - -If we need an additional mark above the letter (or below it) -- no problem, just add the necessary mark character. - -For instance, if we append a character "dot below" (code `\u0323`), then we'll have "S with dots above and below": `Ṩ`. - -For example: - -```js run -alert( 'S\u0307\u0323' ); // Ṩ -``` - -This provides great flexibility, but also an interesting problem: two characters may visually look the same, but be represented with different Unicode compositions. - -For instance: - -```js run -let s1 = 'S\u0307\u0323'; // Ṩ, S + dot above + dot below -let s2 = 'S\u0323\u0307'; // Ṩ, S + dot below + dot above - -alert( `s1: ${s1}, s2: ${s2}` ); - -alert( s1 == s2 ); // false though the characters look identical (?!) -``` - -To solve this, there exists a "Unicode normalization" algorithm that brings each string to the single "normal" form. - -It is implemented by [str.normalize()](mdn:js/String/normalize). - -```js run -alert( "S\u0307\u0323".normalize() == "S\u0323\u0307".normalize() ); // true -``` - -It's funny that in our situation `normalize()` actually brings together a sequence of 3 characters to one: `\u1e68` (S with two dots). - -```js run -alert( "S\u0307\u0323".normalize().length ); // 1 - -alert( "S\u0307\u0323".normalize() == "\u1e68" ); // true -``` - -In reality, this is not always the case. The reason being that the symbol `Ṩ` is "common enough", so Unicode creators included it in the main table and gave it the code. - -If you want to learn more about normalization rules and variants -- they are described in the appendix of the Unicode standard: [Unicode Normalization Forms](https://www.unicode.org/reports/tr15/), but for most practical purposes the information from this section is enough. - ## Summary - There are 3 types of quotes. Backticks allow a string to span multiple lines and embed expressions `${…}`. -- Strings in JavaScript are encoded using UTF-16, with surrogate pairs for rare characters (and these cause glitches). -- We can use special characters like `\n` and insert letters by their Unicode using `\u...`. +- We can use special characters, such as a line break `\n`. - To get a character, use: `[]`. - To get a substring, use: `slice` or `substring`. - To lowercase/uppercase a string, use: `toLowerCase/toUpperCase`. @@ -690,3 +518,5 @@ There are several other helpful methods in strings: - ...and more to be found in the [manual](mdn:js/String). Strings also have methods for doing search/replace with regular expressions. But that's big topic, so it's explained in a separate tutorial section . + +Also, as of now it's important to know that strings are based on Unicode encoding, and hence there're issues with comparisons. There's more about Unicode in the chapter . \ No newline at end of file diff --git a/1-js/99-js-misc/06-unicode/article.md b/1-js/99-js-misc/06-unicode/article.md new file mode 100644 index 000000000..2396fcfaf --- /dev/null +++ b/1-js/99-js-misc/06-unicode/article.md @@ -0,0 +1,172 @@ + +# Unicode, String internals + +```warn header="Advanced knowledge" +The section goes deeper into string internals. This knowledge will be useful for you if you plan to deal with emoji, rare mathematical or hieroglyphic characters or other rare symbols. +``` + +As we already know, JavaScript strings are based on [Unicode](https://en.wikipedia.org/wiki/Unicode): each character is represented by a byte sequence of 1-4 bytes. + +JavaScript allows us to insert a character into a string by specifying its hexadecimal Unicode code with one of these three notations: + +- `\xXX` + + `XX` must be two hexadecimal digits with value between `00` and `FF`, then it's character whose Unicode code is `XX`. + + Because the `\xXX` notation supports only two digits, it can be used only for the first 256 Unicode characters. + + These first 256 characters include latin alphabet, most basic syntax characters and some others. For example, `"\x7A"` is the same as `"z"` (Unicode `U+007A`). + + ```js run + alert( "\x7A" ); // z + alert( "\xA9" ); // ©, the copyright symbol + ``` + +- `\uXXXX` + `XXXX` must be exactly 4 hex digits with the value between `0000` and `FFFF`, then `\uXXXX` is a character whose Unicode code is `XXXX` . + + Characters with Unicode value greater than `U+FFFF` can also be represented with this notation, but in this case we will need to use a so called surrogate pair (we will talk about surrogate pairs later in this chapter). + + ```js run + alert( "\u00A9" ); // ©, the same as \xA9, using the 4-digit hex notation + alert( "\u044F" ); // я, the cyrillic alphabet letter + alert( "\u2191" ); // ↑, the arrow up symbol + ``` + +- `\u{X…XXXXXX}` + + `X…XXXXXX` must be a hexadecimal value of 1 to 6 bytes between `0` and `10FFFF` (the highest code point defined by Unicode). This notation allows us to easily represent all existing Unicode characters. + + ```js run + alert( "\u{20331}" ); // 佫, a rare Chinese hieroglyph (long Unicode) + alert( "\u{1F60D}" ); // 😍, a smiling face symbol (another long Unicode) + ``` + +## Surrogate pairs + +All frequently used characters have 2-byte codes. Letters in most european languages, numbers, and even most hieroglyphs, have a 2-byte representation. + +Initially, JavaScript was based on UTF-16 encoding that only allowed 2 bytes per character. But 2 bytes only allow 65536 combinations and that's not enough for every possible symbol of Unicode. + +So rare symbols that require more than 2 bytes are encoded with a pair of 2-byte characters called "a surrogate pair". + +As a side effect, the length of such symbols is `2`: + +```js run +alert( '𝒳'.length ); // 2, MATHEMATICAL SCRIPT CAPITAL X +alert( '😂'.length ); // 2, FACE WITH TEARS OF JOY +alert( '𩷶'.length ); // 2, a rare Chinese hieroglyph +``` + +That's because surrogate pairs did not exist at the time when JavaScript was created, and thus are not correctly processed by the language! + +We actually have a single symbol in each of the strings above, but the `length` property shows a length of `2`. + +Getting a symbol can also be tricky, because most language features treat surrogate pairs as two characters. + +For example, here we can see two odd characters in the output: + +```js run +alert( '𝒳'[0] ); // shows strange symbols... +alert( '𝒳'[1] ); // ...pieces of the surrogate pair +``` + +Pieces of a surrogate pair have no meaning without each other. So the alerts in the example above actually display garbage. + +Technically, surrogate pairs are also detectable by their codes: if a character has the code in the interval of `0xd800..0xdbff`, then it is the first part of the surrogate pair. The next character (second part) must have the code in interval `0xdc00..0xdfff`. These intervals are reserved exclusively for surrogate pairs by the standard. + +So the methods `String.fromCodePoint` and `str.codePointAt` were added in JavaScript to deal with surrogate pairs. + +They are essentially the same as [String.fromCharCode](mdn:js/String/fromCharCode) and [str.charCodeAt](mdn:js/String/charCodeAt), but they treat surrogate pairs correctly. + +One can see the difference here: + +```js run +// charCodeAt is not surrogate-pair aware, so it gives codes for the 1st part of 𝒳: + +alert( '𝒳'.charCodeAt(0).toString(16) ); // d835 + +// codePointAt is surrogate-pair aware +alert( '𝒳'.codePointAt(0).toString(16) ); // 1d4b3, reads both parts of the surrogate pair +``` + +That said, if we take from position 1 (and that's rather incorrect here), then they both return only the 2nd part of the pair: + +```js run +alert( '𝒳'.charCodeAt(1).toString(16) ); // dcb3 +alert( '𝒳'.codePointAt(1).toString(16) ); // dcb3 +// meaningless 2nd half of the pair +``` + +You will find more ways to deal with surrogate pairs later in the chapter . There are probably special libraries for that too, but nothing famous enough to suggest here. + +````warn header="Takeaway: splitting strings at an arbitrary point is dangerous" +We can't just split a string at an arbitrary position, e.g. take `str.slice(0, 4)` and expect it to be a valid string, e.g.: + +```js run +alert( 'hi 😂'.slice(0, 4) ); // hi [?] +``` + +Here we can see a garbage character (first half of the smile surrogate pair) in the output. + +Just be aware of it if you intend to reliably work with surrogate pairs. May not be a big problem, but at least you should understand what happens. +```` + +## Diacritical marks and normalization + +In many languages, there are symbols that are composed of the base character with a mark above/under it. + +For instance, the letter `a` can be the base character for these characters: `àáâäãåā`. + +Most common "composite" characters have their own code in the Unicode table. But not all of them, because there are too many possible combinations. + +To support arbitrary compositions, Unicode standard allows us to use several Unicode characters: the base character followed by one or many "mark" characters that "decorate" it. + +For instance, if we have `S` followed by the special "dot above" character (code `\u0307`), it is shown as Ṡ. + +```js run +alert( 'S\u0307' ); // Ṡ +``` + +If we need an additional mark above the letter (or below it) -- no problem, just add the necessary mark character. + +For instance, if we append a character "dot below" (code `\u0323`), then we'll have "S with dots above and below": `Ṩ`. + +For example: + +```js run +alert( 'S\u0307\u0323' ); // Ṩ +``` + +This provides great flexibility, but also an interesting problem: two characters may visually look the same, but be represented with different Unicode compositions. + +For instance: + +```js run +let s1 = 'S\u0307\u0323'; // Ṩ, S + dot above + dot below +let s2 = 'S\u0323\u0307'; // Ṩ, S + dot below + dot above + +alert( `s1: ${s1}, s2: ${s2}` ); + +alert( s1 == s2 ); // false though the characters look identical (?!) +``` + +To solve this, there exists a "Unicode normalization" algorithm that brings each string to the single "normal" form. + +It is implemented by [str.normalize()](mdn:js/String/normalize). + +```js run +alert( "S\u0307\u0323".normalize() == "S\u0323\u0307".normalize() ); // true +``` + +It's funny that in our situation `normalize()` actually brings together a sequence of 3 characters to one: `\u1e68` (S with two dots). + +```js run +alert( "S\u0307\u0323".normalize().length ); // 1 + +alert( "S\u0307\u0323".normalize() == "\u1e68" ); // true +``` + +In reality, this is not always the case. The reason being that the symbol `Ṩ` is "common enough", so Unicode creators included it in the main table and gave it the code. + +If you want to learn more about normalization rules and variants -- they are described in the appendix of the Unicode standard: [Unicode Normalization Forms](https://www.unicode.org/reports/tr15/), but for most practical purposes the information from this section is enough. From c27a7b4d409048fe5e841b8ec6c7a649428eeb6f Mon Sep 17 00:00:00 2001 From: Ilya Kantor Date: Sat, 1 Oct 2022 19:39:31 +0200 Subject: [PATCH 39/43] closes #3185 --- 1-js/06-advanced-functions/01-recursion/article.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/1-js/06-advanced-functions/01-recursion/article.md b/1-js/06-advanced-functions/01-recursion/article.md index b7992f162..5ae894474 100644 --- a/1-js/06-advanced-functions/01-recursion/article.md +++ b/1-js/06-advanced-functions/01-recursion/article.md @@ -61,7 +61,7 @@ When `pow(x, n)` is called, the execution splits into two branches: if n==1 = x / pow(x, n) = - \ + \ else = x * pow(x, n - 1) ``` @@ -285,7 +285,7 @@ The iterative `pow` uses a single context changing `i` and `result` in the proce **Any recursion can be rewritten as a loop. The loop variant usually can be made more effective.** -...But sometimes the rewrite is non-trivial, especially when function uses different recursive subcalls depending on conditions and merges their results or when the branching is more intricate. And the optimization may be unneeded and totally not worth the efforts. +...But sometimes the rewrite is non-trivial, especially when a function uses different recursive subcalls depending on conditions and merges their results or when the branching is more intricate. And the optimization may be unneeded and totally not worth the efforts. Recursion can give a shorter code, easier to understand and support. Optimizations are not required in every place, mostly we need a good code, that's why it's used. From c5891761a375ad3d7e55f8ddac52efbec89c0be8 Mon Sep 17 00:00:00 2001 From: Ilya Kantor Date: Sat, 1 Oct 2022 19:45:06 +0200 Subject: [PATCH 40/43] closes #3183 --- 1-js/13-modules/02-import-export/article.md | 37 ++++++++------------- 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/1-js/13-modules/02-import-export/article.md b/1-js/13-modules/02-import-export/article.md index 8af1b3b10..ccbf18cf5 100644 --- a/1-js/13-modules/02-import-export/article.md +++ b/1-js/13-modules/02-import-export/article.md @@ -46,7 +46,7 @@ Also, we can put `export` separately. Here we first declare, and then export: -```js +```js // 📁 say.js function sayHi(user) { alert(`Hello, ${user}!`); @@ -93,25 +93,14 @@ At first sight, "import everything" seems such a cool thing, short to write, why Well, there are few reasons. -1. Modern build tools ([webpack](https://webpack.js.org/) and others) bundle modules together and optimize them to speedup loading and remove unused stuff. - - Let's say, we added a 3rd-party library `say.js` to our project with many functions: - ```js - // 📁 say.js - export function sayHi() { ... } - export function sayBye() { ... } - export function becomeSilent() { ... } - ``` +1. Explicitly listing what to import gives shorter names: `sayHi()` instead of `say.sayHi()`. +2. Explicit list of imports gives better overview of the code structure: what is used and where. It makes code support and refactoring easier. - Now if we only use one of `say.js` functions in our project: - ```js - // 📁 main.js - import {sayHi} from './say.js'; - ``` - ...Then the optimizer will see that and remove the other functions from the bundled code, thus making the build smaller. That is called "tree-shaking". +```smart header="Don't be afraid to import too much" +Modern build tools, such as [webpack](https://webpack.js.org/) and others, bundle modules together and optimize them to speedup loading. They also removed unused imports. -2. Explicitly listing what to import gives shorter names: `sayHi()` instead of `say.sayHi()`. -3. Explicit list of imports gives better overview of the code structure: what is used and where. It makes code support and refactoring easier. +For instance, if you `import * as library` from a huge code library, and then use only few methods, then unused ones [will not be included](https://github.com/webpack/webpack/tree/main/examples/harmony-unused#examplejs) into the optimzed bundle. +``` ## Import "as" @@ -224,7 +213,7 @@ Without `default`, such an export would give an error: export class { // Error! (non-default export needs a name) constructor() {} } -``` +``` ### The "default" name @@ -326,7 +315,7 @@ Imagine, we're writing a "package": a folder with a lot of modules, with some of The file structure could be like this: ``` auth/ - index.js + index.js user.js helpers.js tests/ @@ -372,7 +361,7 @@ The syntax `export ... from ...` is just a shorter notation for such import-expo ```js // 📁 auth/index.js -// re-export login/logout +// re-export login/logout export {login, logout} from './helpers.js'; // re-export the default export as User @@ -380,7 +369,7 @@ export {default as User} from './user.js'; ... ``` -The notable difference of `export ... from` compared to `import/export` is that re-exported modules aren't available in the current file. So inside the above example of `auth/index.js` we can't use re-exported `login/logout` functions. +The notable difference of `export ... from` compared to `import/export` is that re-exported modules aren't available in the current file. So inside the above example of `auth/index.js` we can't use re-exported `login/logout` functions. ### Re-exporting the default export @@ -399,7 +388,7 @@ We can come across two problems with it: 1. `export User from './user.js'` won't work. That would lead to a syntax error. - To re-export the default export, we have to write `export {default as User}`, as in the example above. + To re-export the default export, we have to write `export {default as User}`, as in the example above. 2. `export * from './user.js'` re-exports only named exports, but ignores the default one. @@ -430,7 +419,7 @@ Import: - Importing named exports: - `import {x [as y], ...} from "module"` -- Importing the default export: +- Importing the default export: - `import x from "module"` - `import {default as x} from "module"` - Import all: From 666f3563cc1724e19149ea99ad07c0f19a7ac9af Mon Sep 17 00:00:00 2001 From: Ilya Kantor Date: Sat, 1 Oct 2022 19:53:25 +0200 Subject: [PATCH 41/43] closes #3190 --- 6-data-storage/01-cookie/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/6-data-storage/01-cookie/article.md b/6-data-storage/01-cookie/article.md index b88849457..01c0e1fee 100644 --- a/6-data-storage/01-cookie/article.md +++ b/6-data-storage/01-cookie/article.md @@ -156,7 +156,7 @@ If we set `expires` to a date in the past, the cookie is deleted. - **`max-age=3600`** -Is an alternative to `expires` and specifies the cookie's expiration in seconds from the current moment. +It's an alternative to `expires` and specifies the cookie's expiration in seconds from the current moment. If set to zero or a negative value, the cookie is deleted: From c99d740c017cb87cebb747808fe75d824290754c Mon Sep 17 00:00:00 2001 From: Ilya Kantor Date: Sat, 1 Oct 2022 22:47:15 +0200 Subject: [PATCH 42/43] closes #3179 --- .../02-object-copy/article.md | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/1-js/04-object-basics/02-object-copy/article.md b/1-js/04-object-basics/02-object-copy/article.md index cc2f606a9..e80f748ab 100644 --- a/1-js/04-object-basics/02-object-copy/article.md +++ b/1-js/04-object-basics/02-object-copy/article.md @@ -160,16 +160,17 @@ We can also use the method [Object.assign](https://developer.mozilla.org/en-US/d The syntax is: ```js -Object.assign(dest, src1[, src2, src3...]) +Object.assign(dest, ...sources) ``` - The first argument `dest` is a target object. -- Further arguments `src1, ..., srcN` (can be as many as needed) are source objects. -- It copies the properties of all source objects `src1, ..., srcN` into the target `dest`. In other words, properties of all arguments starting from the second are copied into the first object. -- The call returns `dest`. +- Further arguments is a list of source objects. -For instance, we can use it to merge several objects into one: -```js +It copies the properties of all source objects into the target `dest`, and then returns it as the result. + +For example, we have `user` object, let's add a couple of permissions to it: + +```js run let user = { name: "John" }; let permissions1 = { canView: true }; @@ -181,6 +182,9 @@ Object.assign(user, permissions1, permissions2); */!* // now user = { name: "John", canView: true, canEdit: true } +alert(user.name); // John +alert(user.canView); // true +alert(user.canEdit); // true ``` If the copied property name already exists, it gets overwritten: @@ -193,9 +197,9 @@ Object.assign(user, { name: "Pete" }); alert(user.name); // now user = { name: "Pete" } ``` -We also can use `Object.assign` to replace `for..in` loop for simple cloning: +We also can use `Object.assign` to perform a simple object cloning: -```js +```js run let user = { name: "John", age: 30 @@ -204,9 +208,12 @@ let user = { *!* let clone = Object.assign({}, user); */!* + +alert(clone.name); // John +alert(clone.age); // 30 ``` -It copies all properties of `user` into the empty object and returns it. +Here it copies all properties of `user` into the empty object and returns it. There are also other methods of cloning an object, e.g. using the [spread syntax](info:rest-parameters-spread) `clone = {...user}`, covered later in the tutorial. From 18b1314af4e0ead5a2b10bb4bacd24cecbb3f18e Mon Sep 17 00:00:00 2001 From: Ilya Kantor Date: Sun, 2 Oct 2022 21:09:02 +0200 Subject: [PATCH 43/43] closes #3096 --- .../08-operators/3-primitive-conversions-questions/solution.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/solution.md b/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/solution.md index dfd061cb6..7370b66af 100644 --- a/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/solution.md +++ b/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/solution.md @@ -22,4 +22,4 @@ undefined + 1 = NaN // (6) 4. The subtraction always converts to numbers, so it makes `" -9 "` a number `-9` (ignoring spaces around it). 5. `null` becomes `0` after the numeric conversion. 6. `undefined` becomes `NaN` after the numeric conversion. -7. Space characters, are trimmed off string start and end when a string is converted to a number. Here the whole string consists of space characters, such as `\t`, `\n` and a "regular" space between them. So, similarly to an empty string, it becomes `0`. +7. Space characters are trimmed off string start and end when a string is converted to a number. Here the whole string consists of space characters, such as `\t`, `\n` and a "regular" space between them. So, similarly to an empty string, it becomes `0`.