(253-1)
(that's `9007199254740991`), or less than -(253-1)
for negatives.
+
+To be really precise, the "number" type can store larger integers (up to 1.7976931348623157 * 10308
), but outside of the safe integer range ±(253-1)
there'll be a precision error, because not all digits fit into the fixed 64-bit storage. So an "approximate" value may be stored.
+
+For example, these two numbers (right above the safe range) are the same:
+
+```js
+console.log(9007199254740991 + 1); // 9007199254740992
+console.log(9007199254740991 + 2); // 9007199254740992
+```
+
+So to say, all odd integers greater than (253-1)
can't be stored at all in the "number" type.
+
+For most purposes ±(253-1)
range is quite enough, but sometimes we need the entire range of really big integers, e.g. for cryptography or microsecond-precision timestamps.
+
+`BigInt` type was recently added to the language to represent integers of arbitrary length.
+
+A `BigInt` value is created by appending `n` to the end of an integer:
+
+```js
+// the "n" at the end means it's a BigInt
+const bigInt = 1234567890123456789012345678901234567890n;
+```
+
+As `BigInt` numbers are rarely needed, we don't cover them here, but devoted them a separate chapter (253-1)
(т. е. `9007199254740991`) или меньшими, чем -(253-1)
для отрицательных чисел.
@@ -75,17 +132,62 @@ n = 12.345;
Например, эти два числа (прямо за пределами безопасного диапазона) совпадают:
```js
+<<<<<<< HEAD
console.log(9007199254740991 + 1); // 9007199254740992
console.log(9007199254740991 + 2); // 9007199254740992
+=======
+let str = "Hello";
+let str2 = 'Single quotes are ok too';
+let phrase = `can embed another ${str}`;
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```
То есть все нечетные целые числа, большие чем (253-1)
, вообще не могут храниться в типе `number`.
В большинстве случаев безопасного диапазона чисел от -(253-1)
до (253-1)
вполне достаточно, но иногда нам требуется весь диапазон действительно гигантских целых чисел без каких-либо ограничений или пропущенных значений внутри него. Например, в криптографии или при использовании метки времени («timestamp») с микросекундами.
+<<<<<<< HEAD
Тип `BigInt` был добавлен в JavaScript, чтобы дать возможность работать с целыми числами произвольной длины.
Чтобы создать значение типа `BigInt`, необходимо добавить `n` в конец числового литерала:
+=======
+Double and single quotes are "simple" quotes. There's practically no difference between them in JavaScript.
+
+Backticks are "extended functionality" quotes. They allow us to embed variables and expressions into a string by wrapping them in `${…}`, for example:
+
+```js run
+let name = "John";
+
+// embed a variable
+alert( `Hello, *!*${name}*/!*!` ); // Hello, John!
+
+// embed an expression
+alert( `the result is *!*${1 + 2}*/!*` ); // the result is 3
+```
+
+The expression inside `${…}` is evaluated and the result becomes a part of the string. We can put anything in there: a variable like `name` or an arithmetical expression like `1 + 2` or something more complex.
+
+Please note that this can only be done in backticks. Other quotes don't have this embedding functionality!
+```js run
+alert( "the result is ${1 + 2}" ); // the result is ${1 + 2} (double quotes do nothing)
+```
+
+We'll cover strings more thoroughly in the chapter ±(253-1)
.
+ - `bigint` for integer numbers of arbitrary length.
+ - `string` for strings. A string may have zero or more characters, there's no separate single-character type.
+ - `boolean` for `true`/`false`.
+ - `null` for unknown values -- a standalone type that has a single value `null`.
+ - `undefined` for unassigned values -- a standalone type that has a single value `undefined`.
+ - `symbol` for unique identifiers.
+- And one non-primitive data type:
+ - `object` for more complex data structures.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
Оператор `typeof` позволяет нам увидеть, какой тип данных сохранён в переменной.
+<<<<<<< HEAD
- Имеет две формы: `typeof x` или `typeof(x)`.
- Возвращает строку с именем типа. Например, `"string"`.
- Для `null` возвращается `"object"` -- это ошибка в языке, на самом деле это не объект.
+=======
+- Usually used as `typeof x`, but `typeof(x)` is also possible.
+- Returns a string with the name of the type, like `"string"`.
+- For `null` returns `"object"` -- this is an error in the language, it's not actually an object.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
В следующих главах мы сконцентрируемся на примитивных значениях, а когда познакомимся с ними, перейдём к объектам.
diff --git a/1-js/02-first-steps/06-alert-prompt-confirm/1-simple-page/task.md b/1-js/02-first-steps/06-alert-prompt-confirm/1-simple-page/task.md
index c758136a6f..045cf1de75 100644
--- a/1-js/02-first-steps/06-alert-prompt-confirm/1-simple-page/task.md
+++ b/1-js/02-first-steps/06-alert-prompt-confirm/1-simple-page/task.md
@@ -2,8 +2,14 @@ importance: 4
---
+<<<<<<< HEAD
# Простая страница
Создайте страницу, которая спрашивает имя у пользователя и выводит его.
+=======
+# A simple page
+
+Create a web-page that asks for a name and outputs it.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
[demo]
diff --git a/1-js/02-first-steps/06-alert-prompt-confirm/article.md b/1-js/02-first-steps/06-alert-prompt-confirm/article.md
index 6a0bce1713..0329a037fe 100644
--- a/1-js/02-first-steps/06-alert-prompt-confirm/article.md
+++ b/1-js/02-first-steps/06-alert-prompt-confirm/article.md
@@ -1,3 +1,4 @@
+<<<<<<< HEAD
# Взаимодействие: alert, prompt, confirm
Так как мы будем использовать браузер как демо-среду, нам нужно познакомиться с несколькими функциями его интерфейса, а именно: `alert`, `prompt` и `confirm`.
@@ -7,21 +8,41 @@
С этой функцией мы уже знакомы. Она показывает сообщение и ждёт, пока пользователь нажмёт кнопку "ОК".
Например:
+=======
+# Interaction: alert, prompt, confirm
+
+As we'll be using the browser as our demo environment, let's see a couple of functions to interact with the user: `alert`, `prompt` and `confirm`.
+
+## alert
+
+This one we've seen already. It shows a message and waits for the user to press "OK".
+
+For example:
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```js run
alert("Hello");
```
+<<<<<<< HEAD
Это небольшое окно с сообщением называется *модальным окном*. Понятие *модальное* означает, что пользователь не может взаимодействовать с интерфейсом остальной части страницы, нажимать на другие кнопки и т.д. до тех пор, пока взаимодействует с окном. В данном случае -- пока не будет нажата кнопка "OK".
## prompt
Функция `prompt` принимает два аргумента:
+=======
+The mini-window with the message is called a *modal window*. The word "modal" means that the visitor can't interact with the rest of the page, press other buttons, etc, until they have dealt with the window. In this case -- until they press "OK".
+
+## prompt
+
+The function `prompt` accepts two arguments:
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```js no-beautify
result = prompt(title, [default]);
```
+<<<<<<< HEAD
Этот код отобразит модальное окно с текстом, полем для ввода текста и кнопками OK/Отмена.
`title`
@@ -50,26 +71,68 @@ alert(`Тебе ${age} лет!`); // Тебе 100 лет!
Второй параметр является необязательным, но если не указать его, то Internet Explorer вставит строку `"undefined"` в поле для ввода.
Запустите код в Internet Explorer и посмотрите на результат:
+=======
+It shows a modal window with a text message, an input field for the visitor, and the buttons OK/Cancel.
+
+`title`
+: The text to show the visitor.
+
+`default`
+: An optional second parameter, the initial value for the input field.
+
+```smart header="The square brackets in syntax `[...]`"
+The square brackets around `default` in the syntax above denote that the parameter is optional, not required.
+```
+
+The visitor can type something in the prompt input field and press OK. Then we get that text in the `result`. Or they can cancel the input by pressing Cancel or hitting the `key:Esc` key, then we get `null` as the `result`.
+
+The call to `prompt` returns the text from the input field or `null` if the input was canceled.
+
+For instance:
+
+```js run
+let age = prompt('How old are you?', 100);
+
+alert(`You are ${age} years old!`); // You are 100 years old!
+```
+
+````warn header="In IE: always supply a `default`"
+The second parameter is optional, but if we don't supply it, Internet Explorer will insert the text `"undefined"` into the prompt.
+
+Run this code in Internet Explorer to see:
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```js run
let test = prompt("Test");
```
+<<<<<<< HEAD
Чтобы `prompt` хорошо выглядел в IE, рекомендуется всегда указывать второй параметр:
```js run
let test = prompt("Test", ''); // <-- для IE
+=======
+So, for prompts to look good in IE, we recommend always providing the second argument:
+
+```js run
+let test = prompt("Test", ''); // <-- for IE
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```
````
## confirm
+<<<<<<< HEAD
Синтаксис:
+=======
+The syntax:
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```js
result = confirm(question);
```
+<<<<<<< HEAD
Функция `confirm` отображает модальное окно с текстом вопроса `question` и двумя кнопками: OK и Отмена.
Результат -- `true`, если нажата кнопка OK. В других случаях -- `false`.
@@ -103,3 +166,38 @@ alert( isBoss ); // true, если нажата OK
2. Визуальное отображение окон зависит от браузера, и мы не можем изменить их вид.
Такова цена простоты. Есть другие способы показать более приятные глазу окна с богатой функциональностью для взаимодействия с пользователем, но если "навороты" не имеют значения, то данные методы работают отлично.
+=======
+The function `confirm` shows a modal window with a `question` and two buttons: OK and Cancel.
+
+The result is `true` if OK is pressed and `false` otherwise.
+
+For example:
+
+```js run
+let isBoss = confirm("Are you the boss?");
+
+alert( isBoss ); // true if OK is pressed
+```
+
+## Summary
+
+We covered 3 browser-specific functions to interact with visitors:
+
+`alert`
+: shows a message.
+
+`prompt`
+: shows a message asking the user to input text. It returns the text or, if Cancel button or `key:Esc` is clicked, `null`.
+
+`confirm`
+: shows a message and waits for the user to press "OK" or "Cancel". It returns `true` for OK and `false` for Cancel/`key:Esc`.
+
+All these methods are modal: they pause script execution and don't allow the visitor to interact with the rest of the page until the window has been dismissed.
+
+There are two limitations shared by all the methods above:
+
+1. The exact location of the modal window is determined by the browser. Usually, it's in the center.
+2. The exact look of the window also depends on the browser. We can't modify it.
+
+That is the price for simplicity. There are other ways to show nicer windows and richer interaction with the visitor, but if "bells and whistles" do not matter much, these methods work just fine.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
diff --git a/1-js/02-first-steps/07-type-conversions/article.md b/1-js/02-first-steps/07-type-conversions/article.md
index bd413fa539..876c3c0f68 100644
--- a/1-js/02-first-steps/07-type-conversions/article.md
+++ b/1-js/02-first-steps/07-type-conversions/article.md
@@ -1,3 +1,4 @@
+<<<<<<< HEAD
# Преобразование типов
Чаще всего операторы и функции автоматически приводят переданные им значения к нужному типу.
@@ -19,17 +20,45 @@
Например, `alert(value)` преобразует значение к строке.
Также мы можем использовать функцию `String(value)`, чтобы преобразовать значение к строке:
+=======
+# Type Conversions
+
+Most of the time, operators and functions automatically convert the values given to them to the right type.
+
+For example, `alert` automatically converts any value to a string to show it. Mathematical operations convert values to numbers.
+
+There are also cases when we need to explicitly convert a value to the expected type.
+
+```smart header="Not talking about objects yet"
+In this chapter, we won't cover objects. For now, we'll just be talking about primitives.
+
+Later, after we learn about objects, in the chapter true and false
| `1` and `0` |
+| `string` | Whitespaces (includes spaces, tabs `\t`, newlines `\n` etc.) from the start and end are removed. If the remaining string is empty, the result is `0`. Otherwise, the number is "read" from the string. An error gives `NaN`. |
+
+Examples:
+
+```js run
+alert( Number(" 123 ") ); // 123
+alert( Number("123z") ); // NaN (error reading a number at "z")
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
alert( Number(true) ); // 1
alert( Number(false) ); // 0
```
+<<<<<<< HEAD
Учтите, что `null` и `undefined` ведут себя по-разному. Так, `null` становится нулём, тогда как `undefined` приводится к `NaN`.
Большинство математических операторов также производит данное преобразование, как мы увидим в следующей главе.
@@ -97,11 +173,30 @@ alert( Number(false) ); // 0
- Все остальные значения становятся `true`.
Например:
+=======
+Please note that `null` and `undefined` behave differently here: `null` becomes zero while `undefined` becomes `NaN`.
+
+Most mathematical operators also perform such conversion, we'll see that in the next chapter.
+
+## Boolean Conversion
+
+Boolean conversion is the simplest one.
+
+It happens in logical operations (later we'll meet condition tests and other similar things) but can also be performed explicitly with a call to `Boolean(value)`.
+
+The conversion rule:
+
+- Values that are intuitively "empty", like `0`, an empty string, `null`, `undefined`, and `NaN`, become `false`.
+- Other values become `true`.
+
+For instance:
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```js run
alert( Boolean(1) ); // true
alert( Boolean(0) ); // false
+<<<<<<< HEAD
alert( Boolean("Привет!") ); // true
alert( Boolean("") ); // false
```
@@ -126,10 +221,37 @@ alert( Boolean(" ") ); // пробел это тоже true (любая непу
Преобразование подчиняется правилам:
| Значение | Становится... |
+=======
+alert( Boolean("hello") ); // true
+alert( Boolean("") ); // false
+```
+
+````warn header="Please note: the string with zero `\"0\"` is `true`"
+Some languages (namely PHP) treat `"0"` as `false`. But in JavaScript, a non-empty string is always `true`.
+
+```js run
+alert( Boolean("0") ); // true
+alert( Boolean(" ") ); // spaces, also true (any non-empty string is true)
+```
+````
+
+## Summary
+
+The three most widely used type conversions are to string, to number, and to boolean.
+
+**`String Conversion`** -- Occurs when we output something. Can be performed with `String(value)`. The conversion to string is usually obvious for primitive values.
+
+**`Numeric Conversion`** -- Occurs in math operations. Can be performed with `Number(value)`.
+
+The conversion follows the rules:
+
+| Value | Becomes... |
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
|-------|-------------|
|`undefined`|`NaN`|
|`null`|`0`|
|true / false
| `1 / 0` |
+<<<<<<< HEAD
| `string` | Пробельные символы по краям обрезаются. Далее, если остаётся пустая строка, то получаем `0`, иначе из непустой строки "считывается" число. При ошибке результат `NaN`.|
**`Логическое`** -- Происходит в логических операциях. Может быть вызвано с помощью `Boolean(value)`.
@@ -148,3 +270,23 @@ alert( Boolean(" ") ); // пробел это тоже true (любая непу
- `"0"` и строки из одних пробелов типа `" "` при логическом преобразовании всегда `true`.
В этой главе мы не говорили об объектах. Мы вернёмся к ним позже, в главе a > b
, a < b
.
+- Greater/less than or equals: a >= b
, a <= b
.
+- Equals: `a == b`, please note the double equality sign `==` means the equality test, while a single one `a = b` means an assignment.
+- Not equals: In maths the notation is ≠
, but in JavaScript it's written as a != b
.
+
+In this article we'll learn more about different types of comparisons, how JavaScript makes them, including important peculiarities.
+
+At the end you'll find a good recipe to avoid "JavaScript quirks"-related issues.
+
+## Boolean is the result
+
+All comparison operators return a boolean value:
+
+- `true` -- means "yes", "correct" or "the truth".
+- `false` -- means "no", "wrong" or "not the truth".
+
+For example:
+
+```js run
+alert( 2 > 1 ); // true (correct)
+alert( 2 == 1 ); // false (wrong)
+alert( 2 != 1 ); // true (correct)
+```
+
+A comparison result can be assigned to a variable, just like any value:
+
+```js run
+let result = 5 > 4; // assign the result of the comparison
+alert( result ); // true
+```
+
+## String comparison
+
+To see whether a string is greater than another, JavaScript uses the so-called "dictionary" or "lexicographical" order.
+
+In other words, strings are compared letter-by-letter.
+
+For example:
+
+```js run
+alert( 'Z' > 'A' ); // true
+alert( 'Glow' > 'Glee' ); // true
+alert( 'Bee' > 'Be' ); // true
+```
+
+The algorithm to compare two strings is simple:
+
+1. Compare the first character of both strings.
+2. If the first character from the first string is greater (or less) than the other string's, then the first string is greater (or less) than the second. We're done.
+3. Otherwise, if both strings' first characters are the same, compare the second characters the same way.
+4. Repeat until the end of either string.
+5. If both strings end at the same length, then they are equal. Otherwise, the longer string is greater.
+
+In the first example above, the comparison `'Z' > 'A'` gets to a result at the first step.
+
+The second comparison `'Glow'` and `'Glee'` needs more steps as strings are compared character-by-character:
+
+1. `G` is the same as `G`.
+2. `l` is the same as `l`.
+3. `o` is greater than `e`. Stop here. The first string is greater.
+
+```smart header="Not a real dictionary, but Unicode order"
+The comparison algorithm given above is roughly equivalent to the one used in dictionaries or phone books, but it's not exactly the same.
+
+For instance, case matters. A capital letter `"A"` is not equal to the lowercase `"a"`. Which one is greater? The lowercase `"a"`. Why? Because the lowercase character has a greater index in the internal encoding table JavaScript uses (Unicode). We'll get back to specific details and consequences of this in the chapter (253-1)
или менее чем -(253-1)
. Так как `BigInt` числа нужны достаточно редко, мы рассмотрим их в отдельной главе (253-1)
or be less than -(253-1)
, as we mentioned earlier in the chapter func`string`
. Автоматически вызываемая функция `func` получает строку и встроенные в неё выражения и может их обработать. Подробнее об этом можно прочитать в [документации](mdn:/JavaScript/Reference/template_strings#%D0%A2%D0%B5%D0%B3%D0%BE%D0%B2%D1%8B%D0%B5_%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D1%8B). Если перед строкой есть выражение, то шаблонная строка называется "теговым шаблоном". Это позволяет использовать свою шаблонизацию для строк, но на практике теговые шаблоны применяются редко.
+=======
+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 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).
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
## Спецсимволы
@@ -58,10 +64,17 @@ let guestList = "Guests: // Error: Unexpected token ILLEGAL
```js run
let guestList = "Guests:\n * John\n * Pete\n * Mary";
+<<<<<<< HEAD
alert(guestList); // список гостей, состоящий из нескольких строк
```
В частности, эти две строки эквивалентны, просто записаны по-разному:
+=======
+alert(guestList); // a multiline list of guests, same as above
+```
+
+As a simpler example, these two lines are equal, just written differently:
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```js run
// перевод строки добавлен с помощью символа перевода строки
@@ -74,6 +87,7 @@ World`;
alert(str1 == str2); // true
```
+<<<<<<< HEAD
Есть и другие, реже используемые спецсимволы. Вот список:
| Символ | Описание |
@@ -90,6 +104,30 @@ alert(str1 == str2); // true
Он также используется, если необходимо вставить в строку кавычку.
К примеру:
+=======
+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|
+|`\\`|Backslash|
+|`\t`|Tab|
+|`\b`, `\f`, `\v`| Backspace, Form Feed, Vertical Tab -- mentioned for completeness, coming from old times, not used nowadays (you can forget them right now). |
+
+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( `The backslash: \\` ); // The backslash: \
+```
+
+So-called "escaped" quotes `\'`, `\"`, \\`
are used to insert a quote into the same-quoted string.
+
+For instance:
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```js run
alert( 'I*!*\'*/!*m the Walrus!' ); // *!*I'm*/!* the Walrus!
@@ -97,12 +135,17 @@ alert( 'I*!*\'*/!*m the Walrus!' ); // *!*I'm*/!* the Walrus!
Здесь перед входящей в строку кавычкой необходимо добавить обратный слеш — `\'` — иначе она бы обозначала окончание строки.
+<<<<<<< HEAD
Разумеется, требование экранировать относится только к таким же кавычкам, как те, в которые заключена строка. Так что мы можем применить и более элегантное решение, использовав для этой строки двойные или обратные кавычки:
+=======
+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:
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```js run
-alert( `I'm the Walrus!` ); // I'm the Walrus!
+alert( "I'm the Walrus!" ); // I'm the Walrus!
```
+<<<<<<< HEAD
Заметим, что обратный слеш `\` служит лишь для корректного прочтения строки интерпретатором, но он не записывается в строку после её прочтения. Когда строка сохраняется в оперативную память, в неё не добавляется символ `\`. Вы можете явно видеть это в выводах `alert` в примерах выше.
Но что, если нам надо добавить в строку собственно сам обратный слеш `\`?
@@ -112,6 +155,9 @@ alert( `I'm the Walrus!` ); // I'm the Walrus!
```js run
alert( `The backslash: \\` ); // The backslash: \
```
+=======
+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).
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
## Длина строки
@@ -126,12 +172,20 @@ alert( `My\n`.length ); // 3
```warn header="`length` — это свойство"
Бывает так, что люди с практикой в других языках случайно пытаются вызвать его, добавляя круглые скобки: они пишут `str.length()` вместо `str.length`. Это не работает.
+<<<<<<< HEAD
Так как `str.length` — это числовое свойство, а не функция, добавлять скобки не нужно.
+=======
+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`.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```
## Доступ к символам
+<<<<<<< HEAD
Получить символ, который занимает позицию `pos`, можно с помощью квадратных скобок: `[pos]`. Также можно использовать метод [str.at(pos)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/at). Первый символ занимает нулевую позицию:
+=======
+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:
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```js run
let str = `Hello`;
@@ -142,6 +196,7 @@ alert( str.at(0) ); // H
// получаем последний символ
alert( str[str.length - 1] ); // o
+<<<<<<< HEAD
alert( str.at(-1) ); // o
```
@@ -150,6 +205,16 @@ alert( str.at(-1) ); // o
Таким образом, `.at(-1)` означает последний символ, а `.at(-2)` -- тот, что перед ним, и т.д.
Квадратные скобки всегда возвращают `undefined` для отрицательных индексов. Например:
+=======
+alert( str.at(-1) );
+```
+
+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.
+
+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:
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```js run
let str = `Hello`;
@@ -229,7 +294,11 @@ alert( str.indexOf('widget') ); // -1, совпадений нет, поиск
alert( str.indexOf("id") ); // 1, подстрока "id" найдена на позиции 1 (..idget with id)
```
+<<<<<<< HEAD
Необязательный второй аргумент позволяет начать поиск с определённой позиции.
+=======
+The optional second parameter allows us to start searching from a given position.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
Например, первое вхождение `"id"` — на позиции `1`. Для того, чтобы найти следующее, начнём поиск с позиции `2`:
@@ -300,6 +369,7 @@ if (str.indexOf("Widget") != -1) {
}
```
+<<<<<<< HEAD
#### Трюк с побитовым НЕ
Существует старый трюк с использованием [побитового оператора НЕ](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_NOT) — `~`. Он преобразует число в 32-разрядное целое со знаком (signed 32-bit integer). Дробная часть, в случае, если она присутствует, отбрасывается. Затем все биты числа инвертируются.
@@ -338,6 +408,8 @@ if (~str.indexOf("Widget")) {
На данный момент такой трюк можно встретить только в старом коде, потому что в новом он просто не нужен: есть метод `.includes` (см. ниже).
+=======
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
### includes, startsWith, endsWith
Более современный метод [str.includes(substr, pos)](mdn:js/String/includes) возвращает `true`, если в строке `str` есть подстрока `substr`, либо `false`, если нет.
@@ -360,8 +432,13 @@ alert( "Midget".includes("id", 3) ); // false, поиск начат с пози
Методы [str.startsWith](mdn:js/String/startsWith) и [str.endsWith](mdn:js/String/endsWith) проверяют, соответственно, начинается ли и заканчивается ли строка определённой строкой:
```js run
+<<<<<<< HEAD
alert( "*!*Wid*/!*get".startsWith("Wid") ); // true, "Wid" — начало "Widget"
alert( "Wid*!*get*/!*".endsWith("get") ); // true, "get" — окончание "Widget"
+=======
+alert( "*!*Wid*/!*get".startsWith("Wid") ); // true, "Widget" starts with "Wid"
+alert( "Wid*!*get*/!*".endsWith("get") ); // true, "Widget" ends with "get"
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```
## Получение подстроки
@@ -385,7 +462,11 @@ alert( "Wid*!*get*/!*".endsWith("get") ); // true, "get" — окончание
```js run
let str = "st*!*ringify*/!*";
+<<<<<<< HEAD
alert( str.slice(2) ); // ringify, с позиции 2 и до конца
+=======
+ alert( str.slice(2) ); // 'ringify', from the 2nd position till the end
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```
Также для `start/end` можно задавать отрицательные значения. Это означает, что позиция определена как заданное количество символов *с конца строки*:
@@ -393,6 +474,7 @@ alert( "Wid*!*get*/!*".endsWith("get") ); // true, "get" — окончание
```js run
let str = "strin*!*gif*/!*y";
+<<<<<<< HEAD
// начинаем с позиции 4 справа, а заканчиваем на позиции 1 справа
alert( str.slice(-4, -1) ); // gif
```
@@ -402,6 +484,16 @@ alert( "Wid*!*get*/!*".endsWith("get") ); // true, "get" — окончание
Это — почти то же, что и `slice`, но можно задавать `start` больше `end`.
Если `start` больше `end`, то метод `substring` сработает так, как если бы аргументы были поменяны местами.
+=======
+ // start at the 4th position from the right, end at the 1st from the right
+ alert( str.slice(-4, -1) ); // 'gif'
+ ```
+
+`str.substring(start [, end])`
+: 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).
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
Например:
@@ -427,32 +519,57 @@ alert( "Wid*!*get*/!*".endsWith("get") ); // true, "get" — окончание
```js run
let str = "st*!*ring*/!*ify";
+<<<<<<< HEAD
// ring, получаем 4 символа, начиная с позиции 2
alert( str.substr(2, 4) );
+=======
+ alert( str.substr(2, 4) ); // 'ring', from the 2nd position get 4 characters
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```
Значение первого аргумента может быть отрицательным, тогда позиция определяется с конца:
```js run
let str = "strin*!*gi*/!*fy";
+<<<<<<< HEAD
// gi, получаем 2 символа, начиная с позиции 4 с конца строки
alert( str.substr(-4, 2) );
```
Этот метод находится в [Annex B](https://tc39.es/ecma262/#sec-string.prototype.substr) спецификации языка. Это означает, что его должны поддерживать только браузерные движки JavaScript, и использовать его не рекомендуется. Но на практике он поддерживается везде.
+=======
+ alert( str.substr(-4, 2) ); // 'gi', from the 4th position get 2 characters
+ ```
+
+ This method resides in the [Annex B](https://tc39.es/ecma262/#sec-string.prototype.substr) of the language specification. It means that only browser-hosted Javascript engines should support it, and it's not recommended to use it. In practice, it's supported everywhere.
+
+Let's recap these methods to avoid any confusion:
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
Давайте подытожим, как работают эти методы, чтобы не запутаться:
| метод | выбирает… | отрицательные значения |
|--------|-----------|-----------|
+<<<<<<< HEAD
| `slice(start, end)` | от `start` до `end` (не включая `end`) | можно передавать отрицательные значения |
| `substring(start, end)` | между `start` и `end` (не включая `end`) | отрицательные значения равнозначны `0` |
| `substr(start, length)` | `length` символов, начиная от `start` | значение `start` может быть отрицательным |
+=======
+| `slice(start, end)` | from `start` to `end` (not including `end`) | allows negatives |
+| `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` |
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```smart header="Какой метод выбрать?"
Все эти методы эффективно выполняют задачу. Формально у метода `substr` есть небольшой недостаток: он описан не в собственно спецификации JavaScript, а в приложении к ней — Annex B. Это приложение описывает возможности языка для использования в браузерах, существующие в основном по историческим причинам. Таким образом, в другом окружении, отличном от браузера, он может не поддерживаться. Однако на практике он работает везде.
+<<<<<<< HEAD
Из двух других вариантов, `slice` более гибок, он поддерживает отрицательные аргументы, и его короче писать. Так что, в принципе, можно запомнить только его.
+=======
+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`.
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```
## Сравнение строк
@@ -475,6 +592,7 @@ alert( "Wid*!*get*/!*".endsWith("get") ); // true, "get" — окончание
Это может привести к своеобразным результатам при сортировке названий стран: нормально было бы ожидать, что `Zealand` будет после `Österreich` в списке.
+<<<<<<< HEAD
Чтобы разобраться, что происходит, давайте ознакомимся с внутренним представлением строк в JavaScript.
Строки кодируются в [UTF-16](https://ru.wikipedia.org/wiki/UTF-16). Таким образом, у любого символа есть соответствующий код. Есть специальные методы, позволяющие получить символ по его коду и наоборот.
@@ -486,7 +604,20 @@ alert( "Wid*!*get*/!*".endsWith("get") ); // true, "get" — окончание
// одна и та же буква в нижнем и верхнем регистре
// будет иметь разные коды
alert( "z".codePointAt(0) ); // 122
+=======
+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.
+
+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`:
+
+ ```js run
+ // different case letters have different codes
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
alert( "Z".codePointAt(0) ); // 90
+ alert( "z".codePointAt(0) ); // 122
+ alert( "z".codePointAt(0).toString(16) ); // 7a (if we need a hexadecimal value)
```
`String.fromCodePoint(code)`
@@ -494,9 +625,16 @@ alert( "Wid*!*get*/!*".endsWith("get") ); // true, "get" — окончание
```js run
alert( String.fromCodePoint(90) ); // Z
+<<<<<<< HEAD
```
Давайте сделаем строку, содержащую символы с кодами от `65` до `220` — это латиница и ещё некоторые распространённые символы:
+=======
+ alert( String.fromCodePoint(0x5a) ); // Z (we can also use a hex value as an argument)
+ ```
+
+Now let's see the characters with codes `65..220` (the latin alphabet and a little bit extra) by making a string of them:
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
```js run
let str = '';
@@ -505,6 +643,7 @@ for (let i = 65; i <= 220; i++) {
str += String.fromCodePoint(i);
}
alert( str );
+// Output:
// ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
// ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜ
```
@@ -515,16 +654,27 @@ alert( str );
Символы сравниваются по их кодам. Больший код — больший символ. Код `a` (97) больше кода `Z` (90).
+<<<<<<< HEAD
- Все строчные буквы идут после заглавных, так как их коды больше.
- Некоторые буквы, такие как `Ö`, вообще находятся вне основного алфавита. У этой буквы код больше, чем у любой буквы от `a` до `z`.
### Правильное сравнение [#correct-comparisons]
+=======
+- All lowercase letters go after uppercase letters because their codes are greater.
+- Some letters like `Ö` stand apart from the main alphabet. Here, its code is greater than anything from `a` to `z`.
+
+### Correct comparisons [#correct-comparisons]
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
"Правильный" алгоритм сравнения строк сложнее, чем может показаться, так как разные языки используют разные алфавиты.
Поэтому браузеру нужно знать, какой язык использовать для сравнения.
+<<<<<<< HEAD
К счастью, все современные браузеры (для IE10− нужна дополнительная библиотека [Intl.JS](https://github.com/andyearnshaw/Intl.js/)) поддерживают стандарт [ECMA 402](https://www.ecma-international.org/ecma-402/1.0/ECMA-402.pdf), обеспечивающий правильное сравнение строк на разных языках с учётом их правил.
+=======
+Luckily, modern browsers support the internationalization standard [ECMA-402](https://www.ecma-international.org/publications-and-standards/standards/ecma-402/).
+>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9
Для этого есть соответствующий метод.
@@ -542,6 +692,7 @@ alert( 'Österreich'.localeCompare('Zealand') ); // -1
У этого метода есть два дополнительных аргумента, которые указаны в [документации](mdn:js/String/localeCompare). Первый позволяет указать язык (по умолчанию берётся из окружения) — от него зависит порядок букв. Второй — определить дополнительные правила, такие как чувствительность к регистру, а также следует ли учитывать различия между `"a"` и `"á"`.
+<<<<<<< HEAD
## Итого
- Есть три типа кавычек. Строки, использующие обратные кавычки, могут занимать более одной строки в коде и включать выражения `${…}`.
@@ -562,3 +713,24 @@ alert( 'Österreich'.localeCompare('Zealand') ); // -1
Для строк предусмотрены методы для поиска и замены с использованием регулярных выражений. Но это отдельная большая тема, поэтому ей посвящена отдельная глава учебника handler
вызывается на этом поле для ввода:
+=======
+Function handler
is called on this input:
+
+
+
+
+
+Debounced function debounce(handler, 1000)
is called on this input:
+
+
+
+
+ +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ``` +<<<<<<< HEAD Если нам нужно сделать глобальную переменную уровня всей страницы, можно явно присвоить её объекту `window`, тогда получить значение переменной можно обратившись к `window.user`. Но это должно быть исключением, требующим веской причины. +======= +```smart +In the browser, we can make a variable window-level global by explicitly assigning it to a `window` property, e.g. `window.user = "John"`. + +Then all scripts will see it, both with `type="module"` and without it. + +That said, making such global variables is frowned upon. Please try to avoid them. +``` +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ### Код в модуле выполняется только один раз при импорте +<<<<<<< HEAD Если один и тот же модуль используется в нескольких местах, то его код выполнится только один раз, после чего экспортируемая функциональность передаётся всем импортёрам. Это очень важно для понимания работы модулей. Давайте посмотрим примеры. +======= +If the same module is imported into multiple other modules, its code is executed only once, upon the first import. Then its exports are given to all further importers. + +The one-time evaluation has important consequences, that we should be aware of. + +Let's see a couple of examples. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Во-первых, если при запуске модуля возникают побочные эффекты, например выдаётся сообщение, то импорт модуля в нескольких местах покажет его только один раз - при первом импорте: @@ -133,9 +217,17 @@ import `./alert.js`; // Модуль выполнен! import `./alert.js`; // (ничего не покажет) ``` +<<<<<<< HEAD На практике, задача кода модуля - это обычно инициализация, создание внутренних структур данных, а если мы хотим, чтобы что-то можно было использовать много раз, то экспортируем это. Теперь более продвинутый пример. +======= +The second import shows nothing, because the module has already been evaluated. + +There's a rule: top-level module code should be used for initialization, creation of module-specific internal data structures. If we need to make something callable multiple times - we should export it as a function, like we did with `sayHi` above. + +Now, let's consider a deeper example. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Давайте представим, что модуль экспортирует объект: @@ -160,6 +252,7 @@ import {admin} from './admin.js'; alert(admin.name); // Pete *!* +<<<<<<< HEAD // Оба файла, 1.js и 2.js, импортируют один и тот же объект // Изменения, сделанные в 1.js, будут видны в 2.js */!* @@ -170,44 +263,85 @@ alert(admin.name); // Pete Такое поведение позволяет *конфигурировать* модули при первом импорте. Мы можем установить его свойства один раз, и в дальнейших импортах он будет уже настроенным. Например, модуль `admin.js` предоставляет определённую функциональность, но ожидает передачи учётных данных в объект `admin` извне: +======= +// Both 1.js and 2.js reference the same admin object +// Changes made in 1.js are visible in 2.js +*/!* +``` + +As you can see, when `1.js` changes the `name` property in the imported `admin`, then `2.js` can see the new `admin.name`. + +That's exactly because the module is executed only once. Exports are generated, and then they are shared between importers, so if something changes the `admin` object, other importers will see that. + +**Such behavior is actually very convenient, because it allows us to *configure* modules.** + +In other words, a module can provide a generic functionality that needs a setup. E.g. authentication needs credentials. Then it can export a configuration object expecting the outer code to assign to it. + +Here's the classical pattern: +1. A module exports some means of configuration, e.g. a configuration object. +2. On the first import we initialize it, write to its properties. The top-level application script may do that. +3. Further imports use the module. + +For instance, the `admin.js` module may provide certain functionality (e.g. authentication), but expect the credentials to come into the `config` object from outside: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js // 📁 admin.js -export let admin = { }; +export let config = { }; export function sayHi() { - alert(`Ready to serve, ${admin.name}!`); + alert(`Ready to serve, ${config.user}!`); } ``` +<<<<<<< HEAD В `init.js`, первом скрипте нашего приложения, мы установим `admin.name`. Тогда все это увидят, включая вызовы, сделанные из самого `admin.js`: +======= +Here, `admin.js` exports the `config` object (initially empty, but may have default properties too). + +Then in `init.js`, the first script of our app, we import `config` from it and set `config.user`: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```js // 📁 init.js -import {admin} from './admin.js'; -admin.name = "Pete"; +import {config} from './admin.js'; +config.user = "Pete"; ``` +<<<<<<< HEAD Другой модуль тоже увидит `admin.name`: +======= +...Now the module `admin.js` is configured. -```js -// 📁 other.js -import {admin, sayHi} from './admin.js'; +Further importers can call it, and it correctly shows the current user: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 -alert(admin.name); // *!*Pete*/!* +```js +// 📁 another.js +import {sayHi} from './admin.js'; sayHi(); // Ready to serve, *!*Pete*/!*! ``` + ### import.meta Объект `import.meta` содержит информацию о текущем модуле. +<<<<<<< HEAD Содержимое зависит от окружения. В браузере он содержит ссылку на скрипт или ссылку на текущую веб-страницу, если модуль встроен в HTML: ```html run height=0 ``` @@ -233,18 +367,31 @@ sayHi(); // Ready to serve, *!*Pete*/!*! Есть и несколько других, именно браузерных особенностей скриптов с `type="module"` по сравнению с обычными скриптами. +<<<<<<< HEAD Если вы читаете материал в первый раз или, если не собираетесь использовать модули в браузерах, то сейчас можете пропустить эту секцию. +======= +You may want to skip this section for now if you're reading for the first time, or if you don't use JavaScript in a browser. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ### Модули являются отложенными (deferred) Модули *всегда* выполняются в отложенном (deferred) режиме, точно так же, как скрипты с атрибутом `defer` (описан в главе [](info:script-async-defer)). Это верно и для внешних и встроенных скриптов-модулей. +<<<<<<< HEAD Другими словами: - загрузка внешних модулей, таких как ` @@ -268,14 +419,23 @@ sayHi(); // Ready to serve, *!*Pete*/!*! ``` +<<<<<<< HEAD Пожалуйста, обратите внимание: второй скрипт выполнится раньше, чем первый! Поэтому мы увидим сначала `undefined`, а потом `object`. Это потому, что модули начинают выполняться после полной загрузки страницы. Обычные скрипты запускаются сразу же, поэтому сообщение из обычного скрипта мы видим первым. При использовании модулей нам стоит иметь в виду, что HTML-страница будет показана браузером до того, как выполнятся модули и JavaScript-приложение будет готово к работе. Некоторые функции могут ещё не работать. Нам следует разместить "индикатор загрузки" или что-то ещё, чтобы не смутить этим посетителя. +======= +Please note: the second script actually runs before the first! So we'll see `undefined` first, and then `object`. + +That's because modules are deferred, so we wait for the document to be processed. The regular script runs immediately, so we see its output first. + +When using modules, we should be aware that the HTML page shows up as it loads, and JavaScript modules run after that, so the user may see the page before the JavaScript application is ready. Some functionality may not work yet. We should put "loading indicators", or otherwise ensure that the visitor won't be confused by that. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ### Атрибут async работает во встроенных скриптах +<<<<<<< HEAD Для не-модульных скриптов атрибут `async` работает только на внешних скриптах. Скрипты с ним запускаются сразу по готовности, они не ждут другие скрипты или HTML-документ. Для модулей атрибут `async` работает на любых скриптах. @@ -283,6 +443,15 @@ sayHi(); // Ready to serve, *!*Pete*/!*! Например, в скрипте ниже есть `async`, поэтому он выполнится сразу после загрузки, не ожидая других скриптов. Скрипт выполнит импорт (загрузит `./analytics.js`) и сразу запустится, когда будет готов, даже если HTML документ ещё не будет загружен, или если другие скрипты ещё загружаются. +======= +For non-module scripts, the `async` attribute only works on external scripts. Async scripts run immediately when ready, independently of other scripts or the HTML document. + +For module scripts, it works on inline scripts as well. + +For example, the inline script below has `async`, so it doesn't wait for anything. + +It performs the import (fetches `./analytics.js`) and runs when ready, even if the HTML document is not finished yet, or if other scripts are still pending. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 Это очень полезно, когда модуль ни с чем не связан, например для счётчиков, рекламы, обработчиков событий. @@ -300,7 +469,11 @@ sayHi(); // Ready to serve, *!*Pete*/!*! Внешние скрипты с атрибутом `type="module"` имеют два отличия: +<<<<<<< HEAD 1. Внешние скрипты с одинаковым атрибутом `src` запускаются только один раз: +======= +1. External scripts with the same `src` run only once: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```html @@ -326,11 +499,19 @@ import {sayHi} from 'sayHi'; // Ошибка, "голый" модуль // путь должен быть, например './sayHi.js' или абсолютный ``` +<<<<<<< HEAD Другие окружения, например Node.js, допускают использование "голых" модулей, без путей, так как в них есть свои правила, как работать с такими модулями и где их искать. Но браузеры пока не поддерживают "голые" модули. +======= +Certain environments, like Node.js or bundle tools allow bare modules, without any path, as they have their own ways for finding modules and hooks to fine-tune them. But browsers do not support bare modules yet. +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ### Совместимость, "nomodule" +<<<<<<< HEAD Старые браузеры не понимают атрибут `type="module"`. Скрипты с неизвестным атрибутом `type` просто игнорируются. Мы можем сделать для них "резервный" скрипт при помощи атрибута `nomodule`: +======= +Old browsers do not understand `type="module"`. Scripts of an unknown type are just ignored. For them, it's possible to provide a fallback using the `nomodule` attribute: +>>>>>>> 035c5267ba80fa7b55878f7213cbde449b4092d9 ```html run +