diff --git a/1-js/01-getting-started/1-intro/article.md b/1-js/01-getting-started/1-intro/article.md
index b90be40b76..a34e75915d 100644
--- a/1-js/01-getting-started/1-intro/article.md
+++ b/1-js/01-getting-started/1-intro/article.md
@@ -4,7 +4,11 @@
## Что такое JavaScript?
+<<<<<<< HEAD
Изначально *JavaScript* был создан, чтобы *"сделать веб-страницы живыми"*.
+=======
+*JavaScript* was initially created to "make web pages alive".
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Программы на этом языке называются *скриптами*. Они могут встраиваться в HTML и выполняться автоматически при загрузке веб-страницы.
@@ -12,8 +16,13 @@
Это отличает JavaScript от другого языка - [Java](https://ru.wikipedia.org/wiki/Java).
+<<<<<<< HEAD
```smart header="Почему JavaScript?"
Когда JavaScript создавался, у него было другое имя - "LiveScript". Однако, язык Java был очень популярен в то время, и было решено, что позиционирование JavaScript как "младшего брата" Java будет полезно.
+=======
+```smart header="Why is it called JavaScript?"
+When JavaScript was created, it initially had another name: "LiveScript". But Java was very popular at that time, so it was decided that positioning a new language as a "younger brother" of Java would help.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Со временем JavaScript стал полностью независимым языком со своей собственной спецификацией, называющейся [ECMAScript](http://ru.wikipedia.org/wiki/ECMAScript), и сейчас не имеет никакого отношения к Java.
```
@@ -38,7 +47,11 @@
2. Затем он преобразует ("компилирует") скрипт в машинный язык.
3. После этого машинный код запускается и работает достаточно быстро.
+<<<<<<< HEAD
Движок применяет оптимизации на каждом этапе. Он даже просматривает скомпилированный скрипт во время его работы, анализируя проходящие через него данные, и применяет оптимизации к машинному коду, полагаясь на полученные знания. В результате скрипты работают очень быстро.
+=======
+The engine applies optimizations at each step of the process. It even watches the compiled script as it runs, analyzes the data that flows through it, and further optimizes the machine code based on that knowledge.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```
## Что может JavaScript в браузере?
@@ -63,7 +76,11 @@
Примеры таких ограничений включают в себя:
+<<<<<<< HEAD
- JavaScript на веб-странице не может читать/записывать произвольные файлы на жёстком диске, копировать их или запускать программы. Он не имеет прямого доступа к системным функциям ОС.
+=======
+- JavaScript on a webpage may not read/write arbitrary files on the hard disk, copy them or execute programs. It has no direct access to OS functions.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Современные браузеры позволяют ему работать с файлами, но с ограниченным доступом, и предоставляют его, только если пользователь выполняет определённые действия, такие как "перетаскивание" файла в окно браузера или его выбор с помощью тега ``.
@@ -106,10 +123,18 @@ JavaScript - это единственная браузерная техноло
Примеры таких языков:
+<<<<<<< HEAD
- [CoffeeScript](http://coffeescript.org/) добавляет "синтаксический сахар" для JavaScript. Он вводит более короткий синтаксис, который позволяет писать чистый и лаконичный код. Обычно такое нравится Ruby-программистам.
- [TypeScript](http://www.typescriptlang.org/) концентрируется на добавлении "строгой типизации" для упрощения разработки и поддержки больших и сложных систем. Разработан Microsoft.
- [Flow](http://flow.org/) тоже добавляет типизацию, но иначе. Разработан Facebook.
- [Dart](https://www.dartlang.org/) стоит особняком, потому что имеет собственный движок, работающий вне браузера (например, в мобильных приложениях). Первоначально был предложен Google, как замена JavaScript, но на данный момент необходима его транспиляция для запуска так же, как для вышеперечисленных языков.
+=======
+- [CoffeeScript](http://coffeescript.org/) is a "syntactic sugar" for JavaScript. It introduces shorter syntax, allowing us to write clearer and more precise code. Usually, Ruby devs like it.
+- [TypeScript](http://www.typescriptlang.org/) is concentrated on adding "strict data typing" to simplify the development and support of complex systems. It is developed by Microsoft.
+- [Flow](http://flow.org/) also adds data typing, but in a different way. Developed by Facebook.
+- [Dart](https://www.dartlang.org/) is a standalone language that has its own engine that runs in non-browser environments (like mobile apps), but also can be transpiled to JavaScript. Developed by Google.
+- [Brython](https://brython.info/) is a Python transpiler to JavaScript that allow to write application in pure Python without JavaScript.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Есть и другие. Но даже если мы используем один из этих языков, мы должны знать JavaScript, чтобы действительно понимать, что мы делаем.
diff --git a/1-js/01-getting-started/4-devtools/article.md b/1-js/01-getting-started/4-devtools/article.md
index a4daa6e410..66098ec568 100644
--- a/1-js/01-getting-started/4-devtools/article.md
+++ b/1-js/01-getting-started/4-devtools/article.md
@@ -29,12 +29,23 @@ Chrome и Firefox снискали любовь подавляющего бол
- В консоли мы можем увидеть сообщение об ошибке, отрисованное красным цветом. В нашем случае скрипт содержит неизвестную команду "lalala".
- Справа присутствует ссылка на исходный код `bug.html:12` с номером строки кода, в которой эта ошибка и произошла.
+<<<<<<< HEAD
Под сообщением об ошибке находится синий символ `>`. Он обозначает командную строку, в ней мы можем редактировать и запускать JavaScript-команды. Для их запуска нажмите `key:Enter`.
+=======
+Below the error message, there is a blue `>` symbol. It marks a "command line" where we can type JavaScript commands. Press `key:Enter` to run them.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```smart header="Многострочный ввод"
Обычно при нажатии `key:Enter` введённая строка кода сразу выполняется.
+<<<<<<< HEAD
Чтобы перенести строку, нажмите `key:Shift+Enter`. Так можно вводить более длинный JS-код.
+=======
+```smart header="Multi-line input"
+Usually, when we put a line of code into the console, and then press `key:Enter`, it executes.
+
+To insert multiple lines, press `key:Shift+Enter`. This way one can enter long fragments of JavaScript code.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```
Теперь мы явно видим ошибки, для начала этого вполне достаточно. Мы ещё вернёмся к инструментам разработчика позже и более подробно рассмотрим отладку кода в главе .
@@ -52,11 +63,15 @@ Safari (браузер для Mac, не поддерживается в сист
Откройте Настройки (Preferences) и перейдите к панели "Продвинутые" (Advanced). В самом низу вы найдёте чекбокс:
+<<<<<<< HEAD

Теперь консоль можно активировать нажатием клавиш `key:Cmd+Opt+C`. Также обратите внимание на новый элемент меню "Разработка" ("Develop"). В нем содержится большое количество команд и настроек.
## Итого
+=======
+## Summary
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
- Инструменты разработчика позволяют нам смотреть ошибки, выполнять команды, проверять значение переменных и ещё много всего полезного.
- В большинстве браузеров, работающих под Windows, инструменты разработчика можно открыть, нажав `key:F12`. В Chrome для Mac используйте комбинацию `key:Cmd+Opt+J`, Safari: `key:Cmd+Opt+C` (необходимо предварительное включение "Меню разработчика").
diff --git a/1-js/02-first-steps/01-hello-world/1-hello-alert/index.html b/1-js/02-first-steps/01-hello-world/1-hello-alert/index.html
new file mode 100644
index 0000000000..ff1d871b08
--- /dev/null
+++ b/1-js/02-first-steps/01-hello-world/1-hello-alert/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/1-js/02-first-steps/01-hello-world/1-hello-alert/solution.md b/1-js/02-first-steps/01-hello-world/1-hello-alert/solution.md
index e69de29bb2..81552913b9 100644
--- a/1-js/02-first-steps/01-hello-world/1-hello-alert/solution.md
+++ b/1-js/02-first-steps/01-hello-world/1-hello-alert/solution.md
@@ -0,0 +1,2 @@
+
+[html src="index.html"]
diff --git a/1-js/02-first-steps/01-hello-world/article.md b/1-js/02-first-steps/01-hello-world/article.md
index 667a853086..f697d88a00 100644
--- a/1-js/02-first-steps/01-hello-world/article.md
+++ b/1-js/02-first-steps/01-hello-world/article.md
@@ -43,8 +43,13 @@
Тег `
+
```
Для подключения нескольких скриптов используйте несколько тегов:
diff --git a/1-js/02-first-steps/02-structure/article.md b/1-js/02-first-steps/02-structure/article.md
index 040895d878..ecc17bf766 100644
--- a/1-js/02-first-steps/02-structure/article.md
+++ b/1-js/02-first-steps/02-structure/article.md
@@ -94,7 +94,11 @@ alert("Сейчас будет ошибка")[1, 2].forEach(alert)
## Комментарии
+<<<<<<< HEAD
Со временем программы становятся всё сложнее и сложнее. Возникает необходимость добавлять *комментарии*, которые бы описывали, что делает код и почему.
+=======
+## Comments [#code-comments]
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Комментарии могут находиться в любом месте скрипта. Они не влияют на его выполнение, поскольку движок просто игнорирует их.
@@ -134,8 +138,13 @@ alert('Привет');
alert('Мир');
```
+<<<<<<< HEAD
```smart header="Используйте горячие клавиши!"
В большинстве редакторов строку кода можно закомментировать, нажав комбинацию клавиш `key:Ctrl+/` для однострочного комментария и что-то, вроде `key:Ctrl+Shift+/` -- для многострочных комментариев (выделите кусок кода и нажмите комбинацию клавиш). В системе Mac попробуйте `key:Cmd` вместо `key:Ctrl`.
+=======
+```smart header="Use hotkeys!"
+In most editors, a line of code can be commented out by pressing the `key:Ctrl+/` hotkey for a single-line comment and something like `key:Ctrl+Shift+/` -- for multiline comments (select a piece of code and press the hotkey). For Mac, try `key:Cmd` instead of `key:Ctrl` and `key:Option` instead of `key:Shift`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```
````warn header="Вложенные комментарии не поддерживаются!"
diff --git a/1-js/02-first-steps/03-strict-mode/article.md b/1-js/02-first-steps/03-strict-mode/article.md
index fc47b2b7ad..d0c7066c86 100644
--- a/1-js/02-first-steps/03-strict-mode/article.md
+++ b/1-js/02-first-steps/03-strict-mode/article.md
@@ -19,8 +19,12 @@
...
```
+<<<<<<< HEAD
Позже мы изучим функции (способ группировки команд). Забегая вперёд, заметим, что вместо всего скрипта `"use strict"` можно поставить в начале большинства видов функций. Это позволяет включить строгий режим только в конкретной функции. Но обычно люди используют его для всего файла.
+=======
+Quite soon we're going to learn functions (a way to group commands), so let's note in advance that `"use strict"` can be put at the beginning of a function. Doing that enables strict mode in that function only. But usually people use it for the whole script.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
````warn header="Убедитесь, что \"use strict\" находится в начале"
Проверьте, что `"use strict"` находится в первой исполняемой строке скрипта, иначе строгий режим может не включиться.
@@ -42,16 +46,30 @@ alert("some code");
```warn header="Нет никакого способа отменить `use strict`"
Нет директивы типа `"no use strict"`, которая возвращала бы движок к старому поведению.
+<<<<<<< HEAD
Как только мы входим в строгий режим, отменить это невозможно.
+=======
+Once we enter strict mode, there's no going back.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```
## Консоль браузера
+<<<<<<< HEAD
В будущем, когда вы будете использовать консоль браузера для тестирования функций, обратите внимание, что `use strict` по умолчанию в ней выключен.
+=======
+When you use a [developer console](info:devtools) to run code, please note that it doesn't `use strict` by default.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Иногда, когда `use strict` имеет значение, вы можете получить неправильные результаты.
+<<<<<<< HEAD
Можно использовать `key:Shift+Enter` для ввода нескольких строк и написать в верхней строке `use strict`:
+=======
+So, how to actually `use strict` in the console?
+
+First, you can try to press `key:Shift+Enter` to input multiple lines, and put `use strict` on top, like this:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js
'use strict';
@@ -61,12 +79,17 @@ alert("some code");
В большинстве браузеров, включая Chrome и Firefox, это работает.
+<<<<<<< HEAD
В старых браузерах консоль не учитывает такой `use strict`, там можно "оборачивать" код в функцию, вот так:
+=======
+If it doesn't, e.g. in an old browser, there's an ugly, but reliable way to ensure `use strict`. Put it inside this kind of wrapper:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js
(function() {
'use strict';
+<<<<<<< HEAD
// ...ваш код...
})()
```
@@ -83,3 +106,24 @@ alert("some code");
2. Строгий режим включается путём размещения `"use strict"` в начале скрипта или функции. Некоторые функции языка, такие как "классы" и "модули", автоматически включают строгий режим.
3. Строгий режим поддерживается всеми современными браузерами.
4. Мы рекомендуем всегда начинать скрипты с `"use strict"`. Все примеры в этом руководстве предполагают строгий режим, если (очень редко) не указано иное.
+=======
+ // ...your code here...
+})()
+```
+
+## Should we "use strict"?
+
+The question may sound obvious, but it's not so.
+
+One could recommend to start scripts with `"use strict"`... But you know what's cool?
+
+Modern JavaScript supports "classes" and "modules" - advanced language structures (we'll surely get to them), that enable `use strict` automatically. So we don't need to add the `"use strict"` directive, if we use them.
+
+**So, for now `"use strict";` is a welcome guest at the top of your scripts. Later, when your code is all in classes and modules, you may omit it.**
+
+As of now, we've got to know about `use strict` in general.
+
+In the next chapters, as we learn language features, we'll see the differences between the strict and old modes. Luckily, there aren't many and they actually make our lives better.
+
+All examples in this tutorial assume strict mode unless (very rarely) specified otherwise.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
diff --git a/1-js/02-first-steps/04-variables/article.md b/1-js/02-first-steps/04-variables/article.md
index 85bdd9e261..658272121d 100644
--- a/1-js/02-first-steps/04-variables/article.md
+++ b/1-js/02-first-steps/04-variables/article.md
@@ -81,9 +81,14 @@ let user = 'John'
В принципе, все эти варианты работают одинаково. Так что это вопрос личного вкуса и эстетики.
+<<<<<<< HEAD
````smart header="`var` вместо `let`"
В старых скриптах вы также можете найти другое ключевое слово: `var` вместо `let`:
+=======
+````smart header="`var` instead of `let`"
+In older scripts, you may also find another keyword: `var` instead of `let`:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js
*!*var*/!* message = 'Hello';
@@ -137,8 +142,27 @@ alert(hello); // Hello world!
alert(message); // Hello world!
```
+<<<<<<< HEAD
```smart header="Функциональные языки программирования"
Примечательно, что существуют [функциональные](https://ru.wikipedia.org/wiki/%D0%A4%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%BE%D0%BD%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5) языки программирования, такие как [Scala](http://www.scala-lang.org/) или [Erlang](http://www.erlang.org/), которые запрещают изменять значение переменной.
+=======
+````warn header="Declaring twice triggers an error"
+A variable should be declared only once.
+
+A repeated declaration of the same variable is an error:
+
+```js run
+let message = "This";
+
+// repeated 'let' leads to an error
+let message = "That"; // SyntaxError: 'message' has already been declared
+```
+So, we should declare a variable once and then refer to it without `let`.
+````
+
+```smart header="Functional languages"
+It's interesting to note that there exist [functional](https://en.wikipedia.org/wiki/Functional_programming) programming languages, like [Scala](http://www.scala-lang.org/) or [Erlang](http://www.erlang.org/) that forbid changing variable values.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
В таких языках однажды сохранённое "в коробку" значение остаётся там навсегда. Если нам нужно сохранить что-то другое, язык заставляет нас создать новую коробку (объявить новую переменную). Мы не можем использовать старую переменную.
@@ -195,7 +219,11 @@ let имя = '...';
let 我 = '...';
```
+<<<<<<< HEAD
Технически здесь нет ошибки, такие имена разрешены, но есть международная традиция использовать английский язык в именах переменных. Даже если мы пишем небольшой скрипт, у него может быть долгая жизнь впереди. Людям из других стран, возможно, придётся прочесть его не один раз.
+=======
+Technically, there is no error here. Such names are allowed, but there is an international convention to use English in variable names. Even if we're writing a small script, it may have a long life ahead. People from other countries may need to read it some time.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
````
````warn header="Зарезервированные имена"
diff --git a/1-js/02-first-steps/05-types/article.md b/1-js/02-first-steps/05-types/article.md
index 7d2227179e..907a798013 100644
--- a/1-js/02-first-steps/05-types/article.md
+++ b/1-js/02-first-steps/05-types/article.md
@@ -1,6 +1,14 @@
# Типы данных
+<<<<<<< HEAD
Переменная в JavaScript может содержать любые данные. В один момент там может быть строка, а в другой - число:
+=======
+A value in JavaScript is always of a certain type. For example, a string or a number.
+
+There are eight basic data types in JavaScript. Here, we'll cover them in general and in the next chapters we'll talk about each of them in detail.
+
+We can put any type in a variable. For example, a variable can at one moment be a string and then store a number:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js
// Не будет ошибкой
@@ -8,11 +16,17 @@ let message = "hello";
message = 123456;
```
+<<<<<<< HEAD
Языки программирования, в которых такое возможно, называются "динамически типизированными". Это значит, что типы данных есть, но переменные не привязаны ни к одному из них.
Есть восемь основных типов данных в JavaScript. В этой главе мы рассмотрим их в общем, а в следующих главах поговорим подробнее о каждом.
## Число
+=======
+Programming languages that allow such things, such as JavaScript, are called "dynamically typed", meaning that there exist data types, but variables are not bound to any of them.
+
+## Number
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js
let n = 123;
@@ -63,6 +77,30 @@ n = 12.345;
Подробнее о работе с числами мы поговорим в главе .
## BigInt
+<<<<<<< HEAD
+=======
+
+In JavaScript, the "number" type cannot represent integer values larger than (253-1) (that's `9007199254740991`), or less than -(253-1) for negatives. It's a technical limitation caused by their internal representation.
+
+For most purposes that's quite enough, but sometimes we need really big numbers, 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 . Read it when you need such big numbers.
+
+```smart header="Compatibility issues"
+Right now `BigInt` is supported in Firefox/Chrome/Edge, but not in Safari/IE.
+```
+
+## String
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
В JavaScript тип "number" не может содержать числа больше, чем 253 (или меньше, чем -253 для отрицательных). Это техническое ограничение вызвано их внутренним представлением. 253 - это достаточно большое число, состоящее из 16 цифр, поэтому чаще всего проблем не возникает. Но иногда нам нужны действительно гигантские числа, например в криптографии или при использовании метки времени ("timestamp") с микросекундами.
@@ -71,8 +109,14 @@ n = 12.345;
Чтобы создать значение типа `BigInt`, необходимо добавить `n` в конец числового литерала:
```js
+<<<<<<< HEAD
// символ "n" в конце означает, что это BigInt
const bigInt = 1234567890123456789012345678901234567890n;
+=======
+let str = "Hello";
+let str2 = 'Single quotes are ok too';
+let phrase = `can embed another ${str}`;
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```
Так как `BigInt` числа нужны достаточно редко, мы рассмотрим их в отдельной главе .
@@ -83,7 +127,11 @@ const bigInt = 1234567890123456789012345678901234567890n;
## Строка
+<<<<<<< HEAD
Строка (`string`) в JavaScript должна быть заключена в кавычки.
+=======
+Double and single quotes are "simple" quotes. There's practically no difference between them in JavaScript.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js
let str = "Привет";
@@ -120,13 +168,22 @@ alert( "результат: ${1 + 2}" ); // результат: ${1 + 2} (дво
Мы рассмотрим строки более подробно в главе .
+<<<<<<< HEAD
```smart header="Нет отдельного типа данных для одного символа."
В некоторых языках, например C и Java, для хранения одного символа, например `"a"` или `"%"`, существует отдельный тип. В языках C и Java это `char`.
+=======
+```smart header="There is no *character* type."
+In some languages, there is a special "character" type for a single character. For example, in the C language and in Java it is called "char".
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
В JavaScript подобного типа нет, есть только тип `string`. Строка может содержать один символ или множество.
```
+<<<<<<< HEAD
## Булевый (логический) тип
+=======
+## Boolean (logical type)
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Булевый тип (`boolean`) может принимать только два значения: `true` (истина) и `false` (ложь).
@@ -163,7 +220,11 @@ let age = null;
Это просто специальное значение, которое представляет собой "ничего", "пусто" или "значение неизвестно".
+<<<<<<< HEAD
В приведённом выше коде указано, что переменная `age` неизвестна или не имеет значения по какой-то причине.
+=======
+The code above states that `age` is unknown.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
## Значение "undefined"
@@ -174,30 +235,50 @@ let age = null;
Если переменная объявлена, но ей не присвоено никакого значения, то её значением будет `undefined`:
```js run
-let x;
+let age;
+<<<<<<< HEAD
alert(x); // выведет "undefined"
```
Технически мы можем присвоить значение `undefined` любой переменной:
+=======
+alert(age); // shows "undefined"
+```
+
+Technically, it is possible to explicitly assign `undefined` to a variable:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js run
-let x = 123;
+let age = 100;
-x = undefined;
+// change the value to undefined
+age = undefined;
-alert(x); // "undefined"
+alert(age); // "undefined"
```
+<<<<<<< HEAD
...Но так делать не рекомендуется. Обычно `null` используется для присвоения переменной "пустого" или "неизвестного" значения, а `undefined` -- для проверок, была ли переменная назначена.
+=======
+...But we don't recommend doing that. Normally, one uses `null` to assign an "empty" or "unknown" value to a variable, while `undefined` is reserved as a default initial value for unassigned things.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
## Объекты и символы
Тип `object` (объект) -- особенный.
+<<<<<<< HEAD
Все остальные типы называются "примитивными", потому что их значениями могут быть только простые значения (будь то строка или число, или что-то ещё). Объекты же используются для хранения коллекций данных или более сложных объектов. Мы разберёмся с ними позднее в главе после того, как узнаем больше о примитивах.
Тип `symbol` (символ) используется для создания уникальных идентификаторов объектов. Мы упоминаем здесь о нём для полноты картины, изучим этот тип после объектов.
+=======
+All other types are called "primitive" because their values can contain only a single thing (be it a string or a number or whatever). In contrast, objects are used to store collections of data and more complex entities.
+
+Being that important, objects deserve a special treatment. We'll deal with them later in the chapter , after we learn more about primitives.
+
+The `symbol` type is used to create unique identifiers for objects. We have to mention it here for the sake of completeness, but also postpone the details till we know objects.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
## Оператор typeof [#type-typeof]
@@ -240,13 +321,20 @@ typeof alert // "function" (3)
Последние три строки нуждаются в пояснении:
+<<<<<<< HEAD
1. `Math` - это встроенный объект, который предоставляет математические операции и константы. Мы рассмотрим его подробнее в главе . Здесь он служит лишь примером объекта.
2. Результатом вызова `typeof null` является `"object"`. Это неверно. Это официально признанная ошибка в `typeof`, сохранённая для совместимости. Конечно, `null` не является объектом. Это специальное значение с отдельным типом. Повторимся, это ошибка в языке.
3. Вызов `typeof alert` возвращает `"function"`, потому что `alert` является функцией. Мы изучим функции в следующих главах, где заодно увидим, что в JavaScript нет специального типа "функция". Функции относятся к объектному типу. Но `typeof` обрабатывает их особым образом, возвращая `"function"`. Формально это неверно, но очень удобно на практике.
+=======
+1. `Math` is a built-in object that provides mathematical operations. We will learn it in the chapter . Here, it serves just as an example of an object.
+2. The result of `typeof null` is `"object"`. That's an officially recognized error in `typeof` behavior, coming from the early days of JavaScript and kept for compatibility. Definitely, `null` is not an object. It is a special value with a separate type of its own.
+3. The result of `typeof alert` is `"function"`, because `alert` is a function. We'll study functions in the next chapters where we'll also see that there's no special "function" type in JavaScript. Functions belong to the object type. But `typeof` treats them differently, returning `"function"`. That also comes from the early days of JavaScript. Technically, such behavior isn't correct, but can be convenient in practice.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
## Итого
+<<<<<<< HEAD
В JavaScript есть 8 основных типов.
- `number` для любых чисел: целочисленных или чисел с плавающей точкой, целочисленные значения ограничены диапазоном ±253.
@@ -257,6 +345,18 @@ typeof alert // "function" (3)
- `undefined` для неприсвоенных значений -- отдельный тип, имеющий одно значение `undefined`.
- `object` для более сложных структур данных.
- `symbol` для уникальных идентификаторов.
+=======
+There are 8 basic data types in JavaScript.
+
+- `number` for numbers of any kind: integer or floating-point, integers are limited by ±253.
+- `bigint` is 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`.
+- `object` for more complex data structures.
+- `symbol` for unique identifiers.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Оператор `typeof` позволяет нам увидеть, какой тип данных сохранён в переменной.
diff --git a/1-js/02-first-steps/09-alert-prompt-confirm/1-simple-page/solution.md b/1-js/02-first-steps/06-alert-prompt-confirm/1-simple-page/solution.md
similarity index 100%
rename from 1-js/02-first-steps/09-alert-prompt-confirm/1-simple-page/solution.md
rename to 1-js/02-first-steps/06-alert-prompt-confirm/1-simple-page/solution.md
diff --git a/1-js/02-first-steps/09-alert-prompt-confirm/1-simple-page/task.md b/1-js/02-first-steps/06-alert-prompt-confirm/1-simple-page/task.md
similarity index 100%
rename from 1-js/02-first-steps/09-alert-prompt-confirm/1-simple-page/task.md
rename to 1-js/02-first-steps/06-alert-prompt-confirm/1-simple-page/task.md
diff --git a/1-js/02-first-steps/09-alert-prompt-confirm/article.md b/1-js/02-first-steps/06-alert-prompt-confirm/article.md
similarity index 80%
rename from 1-js/02-first-steps/09-alert-prompt-confirm/article.md
rename to 1-js/02-first-steps/06-alert-prompt-confirm/article.md
index 2ea3c1d38d..587675d5d6 100644
--- a/1-js/02-first-steps/09-alert-prompt-confirm/article.md
+++ b/1-js/02-first-steps/06-alert-prompt-confirm/article.md
@@ -1,5 +1,6 @@
# Взаимодействие: alert, prompt, confirm
+<<<<<<< HEAD:1-js/02-first-steps/09-alert-prompt-confirm/article.md
В этой части учебника мы разбираем "собственно JavaScript", без привязки к браузеру или другой среде выполнения.
Но так как мы будем использовать браузер как демо-среду, нам нужно познакомиться по крайней мере с несколькими функциями его интерфейса, а именно: `alert`, `prompt` и `confirm`.
@@ -14,6 +15,13 @@ alert(message);
```
Этот код отобразит окно в браузере и приостановит дальнейшее выполнение скриптов до тех пор, пока пользователь не нажмёт кнопку "OK".
+=======
+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".
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/02-first-steps/06-alert-prompt-confirm/article.md
Например:
@@ -21,7 +29,11 @@ alert(message);
alert("Hello");
```
+<<<<<<< HEAD:1-js/02-first-steps/09-alert-prompt-confirm/article.md
Это небольшое окно с сообщением называется *модальным окном*. Понятие *модальное* означает, что пользователь не может взаимодействовать с интерфейсом остальной части страницы, нажимать на другие кнопки и т.д. до тех пор, пока взаимодействует с окном. В данном случае -- пока не будет нажата кнопка "OK".
+=======
+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".
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/02-first-steps/06-alert-prompt-confirm/article.md
## prompt
@@ -39,7 +51,15 @@ result = prompt(title, [default]);
`default`
: Необязательный второй параметр, который устанавливает начальное значение в поле для текста в окне.
+<<<<<<< HEAD:1-js/02-first-steps/09-alert-prompt-confirm/article.md
Пользователь может напечатать что-либо в поле ввода и нажать OK. Он также может отменить ввод нажатием на кнопку "Отмена" или нажав на клавишу `key:Esc`.
+=======
+```smart header="The square brackets in syntax `[...]`"
+The square brackets around `default` in the syntax above denote that the parameter as 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`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/02-first-steps/06-alert-prompt-confirm/article.md
Вызов `prompt` вернёт текст, указанный в поле для ввода, или `null`, если ввод отменён пользователем.
diff --git a/1-js/02-first-steps/06-type-conversions/article.md b/1-js/02-first-steps/07-type-conversions/article.md
similarity index 89%
rename from 1-js/02-first-steps/06-type-conversions/article.md
rename to 1-js/02-first-steps/07-type-conversions/article.md
index 7f77b3bae6..8e6ecfda19 100644
--- a/1-js/02-first-steps/06-type-conversions/article.md
+++ b/1-js/02-first-steps/07-type-conversions/article.md
@@ -1,13 +1,24 @@
# Преобразование типов
+<<<<<<< HEAD:1-js/02-first-steps/06-type-conversions/article.md
Чаще всего операторы и функции автоматически приводят переданные им значения к нужному типу.
+=======
+Most of the time, operators and functions automatically convert the values given to them to the right type.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/02-first-steps/07-type-conversions/article.md
Например, `alert` автоматически преобразует любое значение к строке. Математические операторы преобразуют значения к числам.
Есть также случаи, когда нам нужно явно преобразовать значение в ожидаемый тип.
+<<<<<<< HEAD:1-js/02-first-steps/06-type-conversions/article.md
```smart header="Пока что мы не говорим об объектах"
В этой главе мы не касаемся объектов. Сначала мы разберём преобразование примитивных значений. Мы разберём преобразование объектов позже, в главе .
+=======
+```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 we'll see how objects fit in.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/02-first-steps/07-type-conversions/article.md
```
## Строковое преобразование
@@ -81,6 +92,7 @@ alert( Number(false) ); // 0
Учтите, что `null` и `undefined` ведут себя по-разному. Так, `null` становится нулём, тогда как `undefined` приводится к `NaN`.
+<<<<<<< HEAD:1-js/02-first-steps/06-type-conversions/article.md
````smart header="Сложение '+' объединяет строки"
Почти все математические операторы выполняют численное преобразование. Исключение составляет `+`. Если одно из слагаемых является строкой, тогда и все остальные приводятся к строкам.
@@ -93,6 +105,9 @@ alert( '1' + 2 ); // '12' (строка слева)
Так происходит, только если хотя бы один из аргументов является строкой. Во всех остальных случаях значения складываются как числа.
````
+=======
+Most mathematical operators also perform such conversion, we'll see that in the next chapter.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/02-first-steps/07-type-conversions/article.md
## Логическое преобразование
diff --git a/1-js/02-first-steps/07-operators/1-increment-order/solution.md b/1-js/02-first-steps/08-operators/1-increment-order/solution.md
similarity index 100%
rename from 1-js/02-first-steps/07-operators/1-increment-order/solution.md
rename to 1-js/02-first-steps/08-operators/1-increment-order/solution.md
diff --git a/1-js/02-first-steps/07-operators/1-increment-order/task.md b/1-js/02-first-steps/08-operators/1-increment-order/task.md
similarity index 100%
rename from 1-js/02-first-steps/07-operators/1-increment-order/task.md
rename to 1-js/02-first-steps/08-operators/1-increment-order/task.md
diff --git a/1-js/02-first-steps/07-operators/2-assignment-result/solution.md b/1-js/02-first-steps/08-operators/2-assignment-result/solution.md
similarity index 100%
rename from 1-js/02-first-steps/07-operators/2-assignment-result/solution.md
rename to 1-js/02-first-steps/08-operators/2-assignment-result/solution.md
diff --git a/1-js/02-first-steps/07-operators/2-assignment-result/task.md b/1-js/02-first-steps/08-operators/2-assignment-result/task.md
similarity index 100%
rename from 1-js/02-first-steps/07-operators/2-assignment-result/task.md
rename to 1-js/02-first-steps/08-operators/2-assignment-result/task.md
diff --git a/1-js/02-first-steps/06-type-conversions/1-primitive-conversions-questions/solution.md b/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/solution.md
similarity index 96%
rename from 1-js/02-first-steps/06-type-conversions/1-primitive-conversions-questions/solution.md
rename to 1-js/02-first-steps/08-operators/3-primitive-conversions-questions/solution.md
index 2005116c06..41b3945741 100644
--- a/1-js/02-first-steps/06-type-conversions/1-primitive-conversions-questions/solution.md
+++ b/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/solution.md
@@ -10,8 +10,8 @@ true + false = 1
"4" - 2 = 2
"4px" - 2 = NaN
7 / 0 = Infinity
-" -9 " + 5 = " -9 5" // (3)
-" -9 " - 5 = -14 // (4)
+" -9 " + 5 = " -9 5" // (3)
+" -9 " - 5 = -14 // (4)
null + 1 = 1 // (5)
undefined + 1 = NaN // (6)
" \t \n" - 2 = -2 // (7)
diff --git a/1-js/02-first-steps/06-type-conversions/1-primitive-conversions-questions/task.md b/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/task.md
similarity index 100%
rename from 1-js/02-first-steps/06-type-conversions/1-primitive-conversions-questions/task.md
rename to 1-js/02-first-steps/08-operators/3-primitive-conversions-questions/task.md
diff --git a/1-js/02-first-steps/08-operators/4-fix-prompt/solution.md b/1-js/02-first-steps/08-operators/4-fix-prompt/solution.md
new file mode 100644
index 0000000000..04f73fbd0b
--- /dev/null
+++ b/1-js/02-first-steps/08-operators/4-fix-prompt/solution.md
@@ -0,0 +1,32 @@
+The reason is that prompt returns user input as a string.
+
+So variables have values `"1"` and `"2"` respectively.
+
+```js run
+let a = "1"; // prompt("First number?", 1);
+let b = "2"; // prompt("Second number?", 2);
+
+alert(a + b); // 12
+```
+
+What we should to is to convert strings to numbers before `+`. For example, using `Number()` or prepending them with `+`.
+
+For example, right before `prompt`:
+
+```js run
+let a = +prompt("First number?", 1);
+let b = +prompt("Second number?", 2);
+
+alert(a + b); // 3
+```
+
+Or in the `alert`:
+
+```js run
+let a = prompt("First number?", 1);
+let b = prompt("Second number?", 2);
+
+alert(+a + +b); // 3
+```
+
+Using both unary and binary `+` in the latest code. Looks funny, doesn't it?
diff --git a/1-js/02-first-steps/08-operators/4-fix-prompt/task.md b/1-js/02-first-steps/08-operators/4-fix-prompt/task.md
new file mode 100644
index 0000000000..b3ea4a3a3c
--- /dev/null
+++ b/1-js/02-first-steps/08-operators/4-fix-prompt/task.md
@@ -0,0 +1,18 @@
+importance: 5
+
+---
+
+# Fix the addition
+
+Here's a code that asks the user for two numbers and shows their sum.
+
+It works incorrectly. The output in the example below is `12` (for default prompt values).
+
+Why? Fix it. The result should be `3`.
+
+```js run
+let a = prompt("First number?", 1);
+let b = prompt("Second number?", 2);
+
+alert(a + b); // 12
+```
diff --git a/1-js/02-first-steps/07-operators/article.md b/1-js/02-first-steps/08-operators/article.md
similarity index 77%
rename from 1-js/02-first-steps/07-operators/article.md
rename to 1-js/02-first-steps/08-operators/article.md
index b67738b575..14813241b0 100644
--- a/1-js/02-first-steps/07-operators/article.md
+++ b/1-js/02-first-steps/08-operators/article.md
@@ -1,8 +1,16 @@
+<<<<<<< HEAD:1-js/02-first-steps/07-operators/article.md
# Операторы
+=======
+# Basic operators, maths
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/02-first-steps/08-operators/article.md
Многие операторы знакомы нам ещё со школы: сложение `+`, умножение `*`, вычитание `-` и так далее.
+<<<<<<< HEAD:1-js/02-first-steps/07-operators/article.md
В этой главе мы сконцентрируемся на операторах, которые в курсе математики не проходят.
+=======
+In this chapter, we’ll start with simple operators, then concentrate on JavaScript-specific aspects, not covered by school arithmetic.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/02-first-steps/08-operators/article.md
## Термины: "унарный", "бинарный", "операнд"
@@ -28,9 +36,61 @@
Формально мы говорим о двух разных операторах: унарное отрицание (один операнд: меняет знак) и бинарное вычитание (два операнда: вычитает).
+<<<<<<< HEAD:1-js/02-first-steps/07-operators/article.md
## Сложение строк, бинарный +
Давайте посмотрим специальные возможности операторов JavaScript, которые выходят за рамки школьной математики.
+=======
+## Maths
+
+The following math operations are supported:
+
+- Addition `+`,
+- Subtraction `-`,
+- Multiplication `*`,
+- Division `/`,
+- Remainder `%`,
+- Exponentiation `**`.
+
+The first four are straightforward, while `%` and `**` need a few words about them.
+
+### Remainder %
+
+The remainder operator `%`, despite its appearance, is not related to percents.
+
+The result of `a % b` is the [remainder](https://en.wikipedia.org/wiki/Remainder) of the integer division of `a` by `b`.
+
+For instance:
+
+```js run
+alert( 5 % 2 ); // 1, a remainder of 5 divided by 2
+alert( 8 % 3 ); // 2, a remainder of 8 divided by 3
+```
+
+### Exponentiation **
+
+The exponentiation operator `a ** b` multiplies `a` by itself `b` times.
+
+For instance:
+
+```js run
+alert( 2 ** 2 ); // 4 (2 multiplied by itself 2 times)
+alert( 2 ** 3 ); // 8 (2 * 2 * 2, 3 times)
+alert( 2 ** 4 ); // 16 (2 * 2 * 2 * 2, 4 times)
+```
+
+Mathematically, the exponentiation is defined for non-integer numbers as well. For example, a square root is an exponentiation by `1/2`:
+
+```js run
+alert( 4 ** (1/2) ); // 2 (power of 1/2 is the same as a square root)
+alert( 8 ** (1/3) ); // 2 (power of 1/3 is the same as a cubic root)
+```
+
+
+## String concatenation with binary +
+
+Let's meet features of JavaScript operators that are beyond school arithmetics.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/02-first-steps/08-operators/article.md
Обычно при помощи плюса `'+'` складывают числа.
@@ -41,7 +101,11 @@ let s = "моя" + "строка";
alert(s); // моястрока
```
+<<<<<<< HEAD:1-js/02-first-steps/07-operators/article.md
Обратите внимание, если хотя бы один операнд является строкой, то второй будет также преобразован к строке.
+=======
+Note that if any of the operands is a string, then the other one is converted to a string too.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/02-first-steps/08-operators/article.md
Например:
@@ -50,22 +114,35 @@ alert( '1' + 2 ); // "12"
alert( 2 + '1' ); // "21"
```
+<<<<<<< HEAD:1-js/02-first-steps/07-operators/article.md
Причём не важно, справа или слева находится операнд-строка. Правило простое: если хотя бы один из операндов является строкой, то второй будет также преобразован к строке.
Тем не менее, помните, что операции выполняются слева направо. Если перед строкой идут два числа, то числа будут сложены перед преобразованием в строку:
+=======
+See, it doesn't matter whether the first operand is a string or the second one.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/02-first-steps/08-operators/article.md
+Here's a more complex example:
```js run
alert(2 + 2 + '1' ); // будет "41", а не "221"
```
+<<<<<<< HEAD:1-js/02-first-steps/07-operators/article.md
Сложение и преобразование строк - это особенность бинарного плюса `+`. Другие арифметические операторы работают только с числами и всегда преобразуют операнды в числа.
Например, вычитание и деление:
+=======
+Here, operators work one after another. The first `+` sums two numbers, so it returns `4`, then the next `+` adds the string `1` to it, so it's like `4 + '1' = 41`.
+
+The binary `+` is the only operator that supports strings in such a way. Other arithmetic operators work only with numbers and always convert their operands to numbers.
+
+Here's the demo for subtraction and division:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/02-first-steps/08-operators/article.md
```js run
-alert( 2 - '1' ); // 1
-alert( '6' / '2' ); // 3
+alert( 6 - '2' ); // 4, converts '2' to a number
+alert( '6' / '2' ); // 3, converts both operands to numbers
```
## Преобразование к числу, унарный плюс +
@@ -138,17 +215,31 @@ alert( +apples + +oranges ); // 5
| Приоритет | Название | Обозначение |
|------------|------|------|
| ... | ... | ... |
+<<<<<<< HEAD:1-js/02-first-steps/07-operators/article.md
| 16 | унарный плюс | `+` |
| 16 | унарный минус | `-` |
| 14 | умножение | `*` |
| 14 | деление | `/` |
| 13 | сложение | `+` |
| 13 | вычитание | `-` |
+=======
+| 17 | unary plus | `+` |
+| 17 | unary negation | `-` |
+| 16 | exponentiation | `**` |
+| 15 | multiplication | `*` |
+| 15 | division | `/` |
+| 13 | addition | `+` |
+| 13 | subtraction | `-` |
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/02-first-steps/08-operators/article.md
| ... | ... | ... |
| 3 | присваивание | `=` |
| ... | ... | ... |
+<<<<<<< HEAD:1-js/02-first-steps/07-operators/article.md
Так как "унарный плюс" имеет приоритет `16`, который выше, чем `13` у "сложения" (бинарный плюс), то в выражении `"+apples + +oranges"` сначала выполнятся унарные плюсы, а затем сложение.
+=======
+As we can see, the "unary plus" has a priority of `17` which is higher than the `13` of "addition" (binary plus). That's why, in the expression `"+apples + +oranges"`, unary pluses work before the addition.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/02-first-steps/08-operators/article.md
## Присваивание
@@ -162,6 +253,7 @@ let x = 2 * 2 + 1;
alert( x ); // 5
```
+<<<<<<< HEAD:1-js/02-first-steps/07-operators/article.md
Возможно присваивание по цепочке:
```js run
@@ -180,6 +272,13 @@ alert( c ); // 4
````smart header="Оператор `\"=\"` возвращает значение"
Все операторы возвращают значение. Для некоторых это очевидно, например сложение `+` или умножение `*`. Но и оператор присваивания не является исключением.
+=======
+### Assignment = returns a value
+
+The fact of `=` being an operator, not a "magical" language construct has an interesting implication.
+
+Most operators in JavaScript return a value. That's obvious for `+` and `-`, but also true for `=`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/02-first-steps/08-operators/article.md
Вызов `x = value` записывает `value` в `x` *и возвращает его*.
@@ -199,6 +298,7 @@ alert( c ); // 0
В примере выше результатом `(a = b + 1)` будет значение, которое присваивается в `a` (то есть `3`). Потом оно используется для дальнейших вычислений.
+<<<<<<< HEAD:1-js/02-first-steps/07-operators/article.md
Забавное применение присваивания, не так ли? Нам нужно понимать, как это работает, потому что иногда это можно увидеть в JavaScript-библиотеках, но писать самим в таком стиле не рекомендуется. Такие трюки не сделают ваш код более понятным или читабельным.
````
@@ -223,13 +323,62 @@ alert( 6 % 3 ); // 0, остаток от деления 6 на 3
Для натурального числа `b` результат `a ** b` равен `a`, умноженному на само себя `b` раз.
Например:
+=======
+Funny code, isn't it? We should understand how it works, because sometimes we see it in JavaScript libraries.
+
+Although, please don't write the code like that. Such tricks definitely don't make code clearer or readable.
+
+### Chaining assignments
+
+Another interesting feature is the ability to chain assignments:
```js run
-alert( 2 ** 2 ); // 4 (2 * 2)
-alert( 2 ** 3 ); // 8 (2 * 2 * 2)
-alert( 2 ** 4 ); // 16 (2 * 2 * 2 * 2)
+let a, b, c;
+
+*!*
+a = b = c = 2 + 2;
+*/!*
+
+alert( a ); // 4
+alert( b ); // 4
+alert( c ); // 4
```
+Chained assignments evaluate from right to left. First, the rightmost expression `2 + 2` is evaluated and then assigned to the variables on the left: `c`, `b` and `a`. At the end, all the variables share a single value.
+
+Once again, for the purposes of readability it's better to split such code into few lines:
+
+```js
+c = 2 + 2;
+b = c;
+a = c;
+```
+That's easier to read, especially when eye-scanning the code fast.
+
+## Modify-in-place
+
+We often need to apply an operator to a variable and store the new result in that same variable.
+
+For example:
+
+```js
+let n = 2;
+n = n + 5;
+n = n * 2;
+```
+
+This notation can be shortened using the operators `+=` and `*=`:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/02-first-steps/08-operators/article.md
+
+```js run
+let n = 2;
+n += 5; // now n = 7 (same as n = n + 5)
+n *= 2; // now n = 14 (same as n = n * 2)
+
+alert( n ); // 14
+```
+
+<<<<<<< HEAD:1-js/02-first-steps/07-operators/article.md
Оператор работает и для нецелых чисел.
Например:
@@ -237,11 +386,27 @@ alert( 2 ** 4 ); // 16 (2 * 2 * 2 * 2)
```js run
alert( 4 ** (1/2) ); // 2 (степень 1/2 эквивалентна взятию квадратного корня)
alert( 8 ** (1/3) ); // 2 (степень 1/3 эквивалентна взятию кубического корня)
+=======
+Short "modify-and-assign" operators exist for all arithmetical and bitwise operators: `/=`, `-=`, etc.
+
+Such operators have the same precedence as a normal assignment, so they run after most other calculations:
+
+```js run
+let n = 2;
+
+n *= 3 + 5;
+
+alert( n ); // 16 (right part evaluated first, same as n *= 8)
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/02-first-steps/08-operators/article.md
```
## Инкремент/декремент
+<<<<<<< HEAD:1-js/02-first-steps/07-operators/article.md
+=======
+
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/02-first-steps/08-operators/article.md
Одной из наиболее частых операций в JavaScript, как и во многих других языках программирования, является увеличение или уменьшение переменной на единицу.
@@ -368,6 +533,7 @@ counter++;
- RIGHT SHIFT(правый сдвиг) ( `>>` )
- ZERO-FILL RIGHT SHIFT(правый сдвиг с заполнением нулями) ( `>>>` )
+<<<<<<< HEAD:1-js/02-first-steps/07-operators/article.md
Они используются редко. Чтобы понять их, нам нужно углубиться в низкоуровневое представление чисел, и было бы неоптимально делать это прямо сейчас, тем более что они нам не понадобятся в ближайшее время. Если вам интересно, вы можете прочитать статью [Побитовые операторы](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators) на MDN. Практично будет сделать это, когда возникнет реальная необходимость.
## Сокращённая арифметика с присваиванием
@@ -403,6 +569,9 @@ n *= 3 + 5;
alert( n ); // 16 (сначала выполнится правая часть, превратив выражение в n *= 8)
```
+=======
+These operators are used very rarely, when we need to fiddle with numbers on the very lowest (bitwise) level. We won't need these operators any time soon, as web development has little use of them, but in some special areas, such as cryptography, they are useful. You can read the [Bitwise Operators](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators) article on MDN when a need arises.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/02-first-steps/08-operators/article.md
## Оператор запятая
diff --git a/1-js/02-first-steps/08-comparison/1-comparison-questions/solution.md b/1-js/02-first-steps/09-comparison/1-comparison-questions/solution.md
similarity index 60%
rename from 1-js/02-first-steps/08-comparison/1-comparison-questions/solution.md
rename to 1-js/02-first-steps/09-comparison/1-comparison-questions/solution.md
index 9ae106c202..7db31ade42 100644
--- a/1-js/02-first-steps/08-comparison/1-comparison-questions/solution.md
+++ b/1-js/02-first-steps/09-comparison/1-comparison-questions/solution.md
@@ -12,6 +12,7 @@ null === +"\n0\n" → false
Разъяснения:
+<<<<<<< HEAD:1-js/02-first-steps/08-comparison/1-comparison-questions/solution.md
1. Очевидно, `true`.
2. Используется посимвольное сравнение, поэтому `false`.
3. Снова посимвольное сравнение. Первый символ первой строки `"2"` больше, чем первый символ второй `"1"`.
@@ -19,3 +20,12 @@ null === +"\n0\n" → false
5. Строгое сравнение разных типов, поэтому `false`.
6. Аналогично `(4)`, `null` равен только `undefined`.
7. Строгое сравнение разных типов.
+=======
+1. Obviously, true.
+2. Dictionary comparison, hence false. `"a"` is smaller than `"p"`.
+3. Again, dictionary comparison, first char of `"2"` is greater than the first char of `"1"`.
+4. Values `null` and `undefined` equal each other only.
+5. Strict equality is strict. Different types from both sides lead to false.
+6. Similar to `(4)`, `null` only equals `undefined`.
+7. Strict equality of different types.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/02-first-steps/09-comparison/1-comparison-questions/solution.md
diff --git a/1-js/02-first-steps/08-comparison/1-comparison-questions/task.md b/1-js/02-first-steps/09-comparison/1-comparison-questions/task.md
similarity index 100%
rename from 1-js/02-first-steps/08-comparison/1-comparison-questions/task.md
rename to 1-js/02-first-steps/09-comparison/1-comparison-questions/task.md
diff --git a/1-js/02-first-steps/08-comparison/article.md b/1-js/02-first-steps/09-comparison/article.md
similarity index 87%
rename from 1-js/02-first-steps/08-comparison/article.md
rename to 1-js/02-first-steps/09-comparison/article.md
index 0ad4fd4a83..26510e2539 100644
--- a/1-js/02-first-steps/08-comparison/article.md
+++ b/1-js/02-first-steps/09-comparison/article.md
@@ -1,15 +1,34 @@
# Операторы сравнения
+<<<<<<< HEAD:1-js/02-first-steps/08-comparison/article.md
Многие операторы сравнения известны нам из математики:
- Больше/меньше: a > b, a < b.
- Больше/меньше или равно: a >= b, a <= b.
- Равно: `a == b`. Обратите внимание, для сравнения используется двойной знак равенства `=`. Один знак равенства `a = b` означал бы присваивание.
- Не равно. В математике обозначается символом ≠. В JavaScript записывается как знак равенства с предшествующим ему восклицательным знаком: a != b.
+=======
+We know many comparison operators from maths.
+
+In JavaScript they are written like this:
+
+- Greater/less than: 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.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/02-first-steps/09-comparison/article.md
## Результат сравнения имеет логический тип
+<<<<<<< HEAD:1-js/02-first-steps/08-comparison/article.md
Операторы сравнения, как и другие операторы, возвращают значение. Это значение имеет логический тип.
+=======
+All comparison operators return a boolean value:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/02-first-steps/09-comparison/article.md
- `true` -- означает "да", "верно", "истина".
- `false` -- означает "нет", "неверно", "ложь".
@@ -192,6 +211,7 @@ alert( undefined == 0 ); // false (3)
- Сравнения `(1)` и `(2)` возвращают `false`, потому что `undefined` преобразуется в `NaN`, а `NaN` – это специальное числовое значение, которое возвращает `false` при любых сравнениях.
- Нестрогое равенство `(3)` возвращает `false`, потому что `undefined` равно только `null` и ничему больше.
+<<<<<<< HEAD:1-js/02-first-steps/08-comparison/article.md
### Как избежать проблем
Зачем мы рассмотрели все эти примеры? Должны ли мы постоянно помнить обо всех этих особенностях? Не обязательно. Со временем все они станут вам знакомы, но можно избежать проблем, если следовать простому правилу.
@@ -199,6 +219,14 @@ alert( undefined == 0 ); // false (3)
Просто относитесь к любому сравнению с `undefined/null`, кроме строгого равенства `===`, с осторожностью.
Не используйте сравнения `>= > < <=` с переменными, которые могут принимать значения `null/undefined`, если вы не уверены в том, что делаете. Если переменная может принимать эти значения, то добавьте для них отдельные проверки.
+=======
+### Avoid problems
+
+Why did we go over these examples? Should we remember these peculiarities all the time? Well, not really. Actually, these tricky things will gradually become familiar over time, but there's a solid way to avoid problems with them:
+
+- Treat any comparison with `undefined/null` except the strict equality `===` with exceptional care.
+- Don't use comparisons `>= > < <=` with a variable which may be `null/undefined`, unless you're really sure of what you're doing. If a variable can have these values, check for them separately.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/02-first-steps/09-comparison/article.md
## Итого
diff --git a/1-js/02-first-steps/10-ifelse/article.md b/1-js/02-first-steps/10-ifelse/article.md
index 6b0b2e48b5..95228439d8 100644
--- a/1-js/02-first-steps/10-ifelse/article.md
+++ b/1-js/02-first-steps/10-ifelse/article.md
@@ -1,4 +1,8 @@
+<<<<<<< HEAD
# Условные операторы: if, '?'
+=======
+# Conditional branching: if, '?'
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Иногда нам нужно выполнить различные действия в зависимости от условий.
diff --git a/1-js/02-first-steps/11-logical-operators/2-alert-or/solution.md b/1-js/02-first-steps/11-logical-operators/2-alert-or/solution.md
index 935087ab0a..a4879a7484 100644
--- a/1-js/02-first-steps/11-logical-operators/2-alert-or/solution.md
+++ b/1-js/02-first-steps/11-logical-operators/2-alert-or/solution.md
@@ -6,8 +6,14 @@ alert( alert(1) || 2 || alert(3) );
Вызов `alert` не возвращает значения, или, иначе говоря, возвращает `undefined`.
+<<<<<<< HEAD
1. Первый оператор ИЛИ `||` выполнит первый `alert(1)`.
2. Получит `undefined` и пойдёт дальше, ко второму операнду в поисках истинного значения.
3. Так как второй операнд `2` является истинным, то вычисления завершатся, результатом `undefined || 2` будет `2`, которое будет выведено внешним `alert( .... )`.
+=======
+1. The first OR `||` evaluates its left operand `alert(1)`. That shows the first message with `1`.
+2. The `alert` returns `undefined`, so OR goes on to the second operand searching for a truthy value.
+3. The second operand `2` is truthy, so the execution is halted, `2` is returned and then shown by the outer alert.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Второй оператор `||` не будет выполнен, выполнение до `alert(3)` не дойдёт, поэтому `3` выведено не будет.
diff --git a/1-js/02-first-steps/11-logical-operators/article.md b/1-js/02-first-steps/11-logical-operators/article.md
index 3337e324d5..4675f598b8 100644
--- a/1-js/02-first-steps/11-logical-operators/article.md
+++ b/1-js/02-first-steps/11-logical-operators/article.md
@@ -89,29 +89,46 @@ result = value1 || value2 || value3;
Например:
```js run
+<<<<<<< HEAD
alert( 1 || 0 ); // 1
alert( true || 'no matter what' ); // true
alert( null || 1 ); // 1 (первое истинное значение)
alert( null || 0 || 1 ); // 1 (первое истинное значение)
alert( undefined || null || 0 ); // 0 (поскольку все ложно, возвращается последнее значение)
+=======
+alert( 1 || 0 ); // 1 (1 is truthy)
+
+alert( null || 1 ); // 1 (1 is the first truthy value)
+alert( null || 0 || 1 ); // 1 (the first truthy value)
+
+alert( undefined || null || 0 ); // 0 (all falsy, returns the last value)
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```
Это делает возможным более интересное применение оператора по сравнению с "чистым, традиционным, только булевым ИЛИ".
1. **Получение первого истинного значения из списка переменных или выражений.**
+<<<<<<< HEAD
Представим, что у нас имеется ряд переменных, которые могут содержать данные или быть `null/undefined`. Как мы можем найти первую переменную с данными?
С помощью `||`:
+=======
+ For instance, we have `firstName`, `lastName` and `nickName` variables, all optional.
+
+ Let's use OR `||` to choose the one that has the data and show it (or `anonymous` if nothing set):
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js run
- let currentUser = null;
- let defaultUser = "John";
+ let firstName = "";
+ let lastName = "";
+ let nickName = "SuperCoder";
*!*
- let name = currentUser || defaultUser || "unnamed";
+ alert( firstName || lastName || nickName || "Anonymous"); // SuperCoder
*/!*
+<<<<<<< HEAD
alert( name ); // выбирается "John" – первое истинное значение
```
@@ -124,30 +141,45 @@ alert( undefined || null || 0 ); // 0 (поскольку все ложно, в
Это хорошо заметно, когда выражение, указанное в качестве второго аргумента, имеет побочный эффект, например, изменение переменной.
В приведённом ниже примере `x` не изменяется:
+=======
+ ```
- ```js run no-beautify
- let x;
+ If all variables were falsy, `Anonymous` would show up.
+
+2. **Short-circuit evaluation.**
+
+ Another feature of OR `||` operator is the so-called "short-circuit" evaluation.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
- *!*true*/!* || (x = 1);
+ It means that `||` processes its arguments until the first truthy value is reached, and then the value is returned immediately, without even touching the other argument.
+ That importance of this feature becomes obvious if an operand isn't just a value, but an expression with a side effect, such as a variable assignment or a function call.
+
+<<<<<<< HEAD
alert(x); // undefined, потому что (x = 1) не вычисляется
```
Если бы первый аргумент имел значение `false`, то `||` приступил бы к вычислению второго и выполнил операцию присваивания:
+=======
+ In the example below, only the second message is printed:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js run no-beautify
- let x;
-
- *!*false*/!* || (x = 1);
-
- alert(x); // 1
+ *!*true*/!* || alert("not printed");
+ *!*false*/!* || alert("printed");
```
+<<<<<<< HEAD
Присваивание - лишь один пример. Конечно, могут быть и другие побочные эффекты, которые не проявятся, если вычисление до них не дойдёт.
Как мы видим, этот вариант использования `||` является "аналогом `if`". Первый операнд преобразуется в логический. Если он оказывается ложным, начинается вычисление второго.
В большинстве случаев лучше использовать "обычный" `if`, чтобы облегчить понимание кода, но иногда это может быть удобно.
+=======
+ In the first line, the OR `||` operator stops the evaluation immediately upon seeing `true`, so the `alert` isn't run.
+
+ Sometimes, people use this feature to execute commands only if the condition on the left part is falsy.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
## && (И)
@@ -236,7 +268,12 @@ alert( 1 && 2 && 3 ); // 3
Таким образом, код `a && b || c && d` по существу такой же, как если бы выражения `&&` были в круглых скобках: `(a && b) || (c && d)`.
````
+<<<<<<< HEAD
Как и оператор ИЛИ, И `&&` иногда может заменять `if`.
+=======
+````warn header="Don't replace `if` with || or &&"
+Sometimes, people use the AND `&&` operator as a "shorter way to write `if`".
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
К примеру:
@@ -254,14 +291,18 @@ let x = 1;
```js run
let x = 1;
-if (x > 0) {
- alert( 'Greater than zero!' );
-}
+if (x > 0) alert( 'Greater than zero!' );
```
+<<<<<<< HEAD
Однако, как правило, вариант с `if` лучше читается и воспринимается.
Он более очевиден, поэтому лучше использовать его.
+=======
+Although, the variant with `&&` appears shorter, `if` is more obvious and tends to be a little bit more readable. So we recommend using every construct for its purpose: use `if` if we want if and use `&&` if we want AND.
+````
+
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
## ! (НЕ)
diff --git a/1-js/02-first-steps/12-nullish-coalescing-operator/article.md b/1-js/02-first-steps/12-nullish-coalescing-operator/article.md
new file mode 100644
index 0000000000..c72dd91d6e
--- /dev/null
+++ b/1-js/02-first-steps/12-nullish-coalescing-operator/article.md
@@ -0,0 +1,130 @@
+# Nullish coalescing operator '??'
+
+[recent browser="new"]
+
+The nullish coalescing operator `??` provides a short syntax for selecting a first "defined" variable from the list.
+
+The result of `a ?? b` is:
+- `a` if it's not `null` or `undefined`,
+- `b`, otherwise.
+
+So, `x = a ?? b` is a short equivalent to:
+
+```js
+x = (a !== null && a !== undefined) ? a : b;
+```
+
+Here's a longer example.
+
+Imagine, we have a user, and there are variables `firstName`, `lastName` or `nickName` for their first name, last name and the nick name. All of them may be undefined, if the user decided not to enter any value.
+
+We'd like to display the user name: one of these three variables, or show "Anonymous" if nothing is set.
+
+Let's use the `??` operator to select the first defined one:
+
+```js run
+let firstName = null;
+let lastName = null;
+let nickName = "Supercoder";
+
+// show the first not-null/undefined value
+*!*
+alert(firstName ?? lastName ?? nickName ?? "Anonymous"); // Supercoder
+*/!*
+```
+
+## Comparison with ||
+
+The OR `||` operator can be used in the same way as `??`. Actually, we can replace `??` with `||` in the code above and get the same result, as it was described in the [previous chapter](info:logical-operators#or-finds-the-first-truthy-value).
+
+The important difference is that:
+- `||` returns the first *truthy* value.
+- `??` returns the first *defined* value.
+
+This matters a lot when we'd like to treat `null/undefined` differently from `0`.
+
+For example, consider this:
+
+```js
+height = height ?? 100;
+```
+
+This sets `height` to `100` if it's not defined.
+
+Let's compare it with `||`:
+
+```js run
+let height = 0;
+
+alert(height || 100); // 100
+alert(height ?? 100); // 0
+```
+
+Here, `height || 100` treats zero height as unset, same as `null`, `undefined` or any other falsy value. So the result is `100`.
+
+The `height ?? 100` returns `100` only if `height` is exactly `null` or `undefined`. So the `alert` shows the height value `0` "as is".
+
+Which behavior is better depends on a particular use case. When zero height is a valid value, then `??` is preferrable.
+
+## Precedence
+
+The precedence of the `??` operator is rather low: `5` in the [MDN table](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table).
+
+So `??` is evaluated after most other operations, but before `=` and `?`.
+
+If we need to choose a value with `??` in a complex expression, then consider adding parentheses:
+
+```js run
+let height = null;
+let width = null;
+
+// important: use parentheses
+let area = (height ?? 100) * (width ?? 50);
+
+alert(area); // 5000
+```
+
+Otherwise, if we omit parentheses, `*` has the higher precedence than `??` and would run first.
+
+That would work be the same as:
+
+```js
+// probably not correct
+let area = height ?? (100 * width) ?? 50;
+```
+
+There's also a related language-level limitation.
+
+**Due to safety reasons, it's forbidden to use `??` together with `&&` and `||` operators.**
+
+The code below triggers a syntax error:
+
+```js run
+let x = 1 && 2 ?? 3; // Syntax error
+```
+
+The limitation is surely debatable, but it was added to the language specification with the purpose to avoid programming mistakes, as people start to switch to `??` from `||`.
+
+Use explicit parentheses to work around it:
+
+```js run
+*!*
+let x = (1 && 2) ?? 3; // Works
+*/!*
+
+alert(x); // 2
+```
+
+## Summary
+
+- The nullish coalescing operator `??` provides a short way to choose a "defined" value from the list.
+
+ It's used to assign default values to variables:
+
+ ```js
+ // set height=100, if height is null or undefined
+ height = height ?? 100;
+ ```
+
+- The operator `??` has a very low precedence, a bit higher than `?` and `=`.
+- It's forbidden to use it with `||` or `&&` without explicit parentheses.
diff --git a/1-js/02-first-steps/12-while-for/1-loop-last-value/solution.md b/1-js/02-first-steps/13-while-for/1-loop-last-value/solution.md
similarity index 100%
rename from 1-js/02-first-steps/12-while-for/1-loop-last-value/solution.md
rename to 1-js/02-first-steps/13-while-for/1-loop-last-value/solution.md
diff --git a/1-js/02-first-steps/12-while-for/1-loop-last-value/task.md b/1-js/02-first-steps/13-while-for/1-loop-last-value/task.md
similarity index 100%
rename from 1-js/02-first-steps/12-while-for/1-loop-last-value/task.md
rename to 1-js/02-first-steps/13-while-for/1-loop-last-value/task.md
diff --git a/1-js/02-first-steps/12-while-for/2-which-value-while/solution.md b/1-js/02-first-steps/13-while-for/2-which-value-while/solution.md
similarity index 100%
rename from 1-js/02-first-steps/12-while-for/2-which-value-while/solution.md
rename to 1-js/02-first-steps/13-while-for/2-which-value-while/solution.md
diff --git a/1-js/02-first-steps/12-while-for/2-which-value-while/task.md b/1-js/02-first-steps/13-while-for/2-which-value-while/task.md
similarity index 100%
rename from 1-js/02-first-steps/12-while-for/2-which-value-while/task.md
rename to 1-js/02-first-steps/13-while-for/2-which-value-while/task.md
diff --git a/1-js/02-first-steps/12-while-for/3-which-value-for/solution.md b/1-js/02-first-steps/13-while-for/3-which-value-for/solution.md
similarity index 100%
rename from 1-js/02-first-steps/12-while-for/3-which-value-for/solution.md
rename to 1-js/02-first-steps/13-while-for/3-which-value-for/solution.md
diff --git a/1-js/02-first-steps/12-while-for/3-which-value-for/task.md b/1-js/02-first-steps/13-while-for/3-which-value-for/task.md
similarity index 100%
rename from 1-js/02-first-steps/12-while-for/3-which-value-for/task.md
rename to 1-js/02-first-steps/13-while-for/3-which-value-for/task.md
diff --git a/1-js/02-first-steps/12-while-for/4-for-even/solution.md b/1-js/02-first-steps/13-while-for/4-for-even/solution.md
similarity index 100%
rename from 1-js/02-first-steps/12-while-for/4-for-even/solution.md
rename to 1-js/02-first-steps/13-while-for/4-for-even/solution.md
diff --git a/1-js/02-first-steps/12-while-for/4-for-even/task.md b/1-js/02-first-steps/13-while-for/4-for-even/task.md
similarity index 100%
rename from 1-js/02-first-steps/12-while-for/4-for-even/task.md
rename to 1-js/02-first-steps/13-while-for/4-for-even/task.md
diff --git a/1-js/02-first-steps/12-while-for/5-replace-for-while/solution.md b/1-js/02-first-steps/13-while-for/5-replace-for-while/solution.md
similarity index 100%
rename from 1-js/02-first-steps/12-while-for/5-replace-for-while/solution.md
rename to 1-js/02-first-steps/13-while-for/5-replace-for-while/solution.md
diff --git a/1-js/02-first-steps/12-while-for/5-replace-for-while/task.md b/1-js/02-first-steps/13-while-for/5-replace-for-while/task.md
similarity index 100%
rename from 1-js/02-first-steps/12-while-for/5-replace-for-while/task.md
rename to 1-js/02-first-steps/13-while-for/5-replace-for-while/task.md
diff --git a/1-js/02-first-steps/12-while-for/6-repeat-until-correct/solution.md b/1-js/02-first-steps/13-while-for/6-repeat-until-correct/solution.md
similarity index 100%
rename from 1-js/02-first-steps/12-while-for/6-repeat-until-correct/solution.md
rename to 1-js/02-first-steps/13-while-for/6-repeat-until-correct/solution.md
diff --git a/1-js/02-first-steps/12-while-for/6-repeat-until-correct/task.md b/1-js/02-first-steps/13-while-for/6-repeat-until-correct/task.md
similarity index 100%
rename from 1-js/02-first-steps/12-while-for/6-repeat-until-correct/task.md
rename to 1-js/02-first-steps/13-while-for/6-repeat-until-correct/task.md
diff --git a/1-js/02-first-steps/12-while-for/7-list-primes/solution.md b/1-js/02-first-steps/13-while-for/7-list-primes/solution.md
similarity index 100%
rename from 1-js/02-first-steps/12-while-for/7-list-primes/solution.md
rename to 1-js/02-first-steps/13-while-for/7-list-primes/solution.md
diff --git a/1-js/02-first-steps/12-while-for/7-list-primes/task.md b/1-js/02-first-steps/13-while-for/7-list-primes/task.md
similarity index 100%
rename from 1-js/02-first-steps/12-while-for/7-list-primes/task.md
rename to 1-js/02-first-steps/13-while-for/7-list-primes/task.md
diff --git a/1-js/02-first-steps/12-while-for/article.md b/1-js/02-first-steps/13-while-for/article.md
similarity index 97%
rename from 1-js/02-first-steps/12-while-for/article.md
rename to 1-js/02-first-steps/13-while-for/article.md
index 7ba0c3740d..d68fc4c42b 100644
--- a/1-js/02-first-steps/12-while-for/article.md
+++ b/1-js/02-first-steps/13-while-for/article.md
@@ -212,7 +212,7 @@ for (;;) {
Например, следующий код подсчитывает сумму вводимых чисел до тех пор, пока посетитель их вводит, а затем – выдаёт:
-```js
+```js run
let sum = 0;
while (true) {
@@ -256,7 +256,7 @@ for (let i = 0; i < 10; i++) {
````smart header="Директива `continue` позволяет избегать вложенности"
Цикл, который обрабатывает только нечётные значения, мог бы выглядеть так:
-```js
+```js run
for (let i = 0; i < 10; i++) {
if (i % 2) {
@@ -268,7 +268,11 @@ for (let i = 0; i < 10; i++) {
С технической точки зрения он полностью идентичен. Действительно, вместо `continue` можно просто завернуть действия в блок `if`.
+<<<<<<< HEAD:1-js/02-first-steps/12-while-for/article.md
Однако мы получили дополнительный уровень вложенности фигурных скобок. Если код внутри `if` более длинный, то это ухудшает читаемость, в отличие от варианта с `continue`.
+=======
+But as a side-effect, this created one more level of nesting (the `alert` call inside the curly braces). If the code inside of `if` is longer than a few lines, that may decrease the overall readability.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/02-first-steps/13-while-for/article.md
````
````warn header="Нельзя использовать `break/continue` справа от оператора '?'"
diff --git a/1-js/02-first-steps/13-switch/1-rewrite-switch-if-else/solution.md b/1-js/02-first-steps/14-switch/1-rewrite-switch-if-else/solution.md
similarity index 100%
rename from 1-js/02-first-steps/13-switch/1-rewrite-switch-if-else/solution.md
rename to 1-js/02-first-steps/14-switch/1-rewrite-switch-if-else/solution.md
diff --git a/1-js/02-first-steps/13-switch/1-rewrite-switch-if-else/task.md b/1-js/02-first-steps/14-switch/1-rewrite-switch-if-else/task.md
similarity index 100%
rename from 1-js/02-first-steps/13-switch/1-rewrite-switch-if-else/task.md
rename to 1-js/02-first-steps/14-switch/1-rewrite-switch-if-else/task.md
diff --git a/1-js/02-first-steps/13-switch/2-rewrite-if-switch/solution.md b/1-js/02-first-steps/14-switch/2-rewrite-if-switch/solution.md
similarity index 100%
rename from 1-js/02-first-steps/13-switch/2-rewrite-if-switch/solution.md
rename to 1-js/02-first-steps/14-switch/2-rewrite-if-switch/solution.md
diff --git a/1-js/02-first-steps/13-switch/2-rewrite-if-switch/task.md b/1-js/02-first-steps/14-switch/2-rewrite-if-switch/task.md
similarity index 100%
rename from 1-js/02-first-steps/13-switch/2-rewrite-if-switch/task.md
rename to 1-js/02-first-steps/14-switch/2-rewrite-if-switch/task.md
diff --git a/1-js/02-first-steps/13-switch/article.md b/1-js/02-first-steps/14-switch/article.md
similarity index 99%
rename from 1-js/02-first-steps/13-switch/article.md
rename to 1-js/02-first-steps/14-switch/article.md
index 551d990f8f..7f356dc2da 100644
--- a/1-js/02-first-steps/13-switch/article.md
+++ b/1-js/02-first-steps/14-switch/article.md
@@ -117,7 +117,7 @@ switch (+a) {
Для примера, выполним один и тот же код для `case 3` и `case 5`, сгруппировав их:
```js run no-beautify
-let a = 2 + 2;
+let a = 3;
switch (a) {
case 4:
diff --git a/1-js/02-first-steps/14-function-basics/1-if-else-required/solution.md b/1-js/02-first-steps/15-function-basics/1-if-else-required/solution.md
similarity index 100%
rename from 1-js/02-first-steps/14-function-basics/1-if-else-required/solution.md
rename to 1-js/02-first-steps/15-function-basics/1-if-else-required/solution.md
diff --git a/1-js/02-first-steps/14-function-basics/1-if-else-required/task.md b/1-js/02-first-steps/15-function-basics/1-if-else-required/task.md
similarity index 100%
rename from 1-js/02-first-steps/14-function-basics/1-if-else-required/task.md
rename to 1-js/02-first-steps/15-function-basics/1-if-else-required/task.md
diff --git a/1-js/02-first-steps/14-function-basics/2-rewrite-function-question-or/solution.md b/1-js/02-first-steps/15-function-basics/2-rewrite-function-question-or/solution.md
similarity index 100%
rename from 1-js/02-first-steps/14-function-basics/2-rewrite-function-question-or/solution.md
rename to 1-js/02-first-steps/15-function-basics/2-rewrite-function-question-or/solution.md
diff --git a/1-js/02-first-steps/14-function-basics/2-rewrite-function-question-or/task.md b/1-js/02-first-steps/15-function-basics/2-rewrite-function-question-or/task.md
similarity index 100%
rename from 1-js/02-first-steps/14-function-basics/2-rewrite-function-question-or/task.md
rename to 1-js/02-first-steps/15-function-basics/2-rewrite-function-question-or/task.md
diff --git a/1-js/02-first-steps/14-function-basics/3-min/solution.md b/1-js/02-first-steps/15-function-basics/3-min/solution.md
similarity index 100%
rename from 1-js/02-first-steps/14-function-basics/3-min/solution.md
rename to 1-js/02-first-steps/15-function-basics/3-min/solution.md
diff --git a/1-js/02-first-steps/14-function-basics/3-min/task.md b/1-js/02-first-steps/15-function-basics/3-min/task.md
similarity index 100%
rename from 1-js/02-first-steps/14-function-basics/3-min/task.md
rename to 1-js/02-first-steps/15-function-basics/3-min/task.md
diff --git a/1-js/02-first-steps/14-function-basics/4-pow/solution.md b/1-js/02-first-steps/15-function-basics/4-pow/solution.md
similarity index 100%
rename from 1-js/02-first-steps/14-function-basics/4-pow/solution.md
rename to 1-js/02-first-steps/15-function-basics/4-pow/solution.md
diff --git a/1-js/02-first-steps/14-function-basics/4-pow/task.md b/1-js/02-first-steps/15-function-basics/4-pow/task.md
similarity index 100%
rename from 1-js/02-first-steps/14-function-basics/4-pow/task.md
rename to 1-js/02-first-steps/15-function-basics/4-pow/task.md
diff --git a/1-js/02-first-steps/14-function-basics/article.md b/1-js/02-first-steps/15-function-basics/article.md
similarity index 94%
rename from 1-js/02-first-steps/14-function-basics/article.md
rename to 1-js/02-first-steps/15-function-basics/article.md
index 9806625447..66303ec01d 100644
--- a/1-js/02-first-steps/14-function-basics/article.md
+++ b/1-js/02-first-steps/15-function-basics/article.md
@@ -214,23 +214,38 @@ function showMessage(from, text = anotherFunction()) {
В примере выше `anotherFunction()` будет вызываться каждый раз, когда `showMessage()` вызывается без параметра `text`.
```
+<<<<<<< HEAD:1-js/02-first-steps/14-function-basics/article.md
````smart header="Использование параметров по умолчанию в ранних версиях JavaScript"
Ранние версии JavaScript не поддерживали параметры по умолчанию. Поэтому существуют альтернативные способы, которые могут встречаться в старых скриптах.
Например, явная проверка на `undefined`:
+=======
+### Alternative default parameters
-```js
-function showMessage(from, text) {
+Sometimes it makes sense to set default values for parameters not in the function declaration, but at a later stage, during its execution.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/02-first-steps/15-function-basics/article.md
+
+To check for an omitted parameter, we can compare it with `undefined`:
+
+```js run
+function showMessage(text) {
*!*
if (text === undefined) {
+<<<<<<< HEAD:1-js/02-first-steps/14-function-basics/article.md
text = 'текст не добавлен';
+=======
+ text = 'empty message';
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/02-first-steps/15-function-basics/article.md
}
*/!*
- alert( from + ": " + text );
+ alert(text);
}
+
+showMessage(); // empty message
```
+<<<<<<< HEAD:1-js/02-first-steps/14-function-basics/article.md
...Или с помощью оператора `||`:
```js
@@ -241,7 +256,30 @@ function showMessage(from, text) {
}
```
````
+=======
+...Or we could use the `||` operator:
+```js
+// if text parameter is omitted or "" is passed, set it to 'empty'
+function showMessage(text) {
+ text = text || 'empty';
+ ...
+}
+```
+
+Modern JavaScript engines support the [nullish coalescing operator](info:nullish-coalescing-operator) `??`, it's better when falsy values, such as `0`, are considered regular:
+
+```js run
+// if there's no "count" parameter, show "unknown"
+function showCount(count) {
+ alert(count ?? "unknown");
+}
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/02-first-steps/15-function-basics/article.md
+
+showCount(0); // 0
+showCount(null); // unknown
+showCount(); // unknown
+```
## Возврат значения
@@ -264,7 +302,7 @@ alert( result ); // 3
```js run
function checkAge(age) {
- if (age > 18) {
+ if (age >= 18) {
*!*
return true;
*/!*
diff --git a/1-js/02-first-steps/16-function-expressions/article.md b/1-js/02-first-steps/16-function-expressions/article.md
new file mode 100644
index 0000000000..a8ccd6c6c8
--- /dev/null
+++ b/1-js/02-first-steps/16-function-expressions/article.md
@@ -0,0 +1,368 @@
+# Function expressions
+
+In JavaScript, a function is not a "magical language structure", but a special kind of value.
+
+The syntax that we used before is called a *Function Declaration*:
+
+```js
+function sayHi() {
+ alert( "Hello" );
+}
+```
+
+There is another syntax for creating a function that is called a *Function Expression*.
+
+It looks like this:
+
+```js
+let sayHi = function() {
+ alert( "Hello" );
+};
+```
+
+Here, the function is created and assigned to the variable explicitly, like any other value. No matter how the function is defined, it's just a value stored in the variable `sayHi`.
+
+The meaning of these code samples is the same: "create a function and put it into the variable `sayHi`".
+
+We can even print out that value using `alert`:
+
+```js run
+function sayHi() {
+ alert( "Hello" );
+}
+
+*!*
+alert( sayHi ); // shows the function code
+*/!*
+```
+
+Please note that the last line does not run the function, because there are no parentheses after `sayHi`. There are programming languages where any mention of a function name causes its execution, but JavaScript is not like that.
+
+In JavaScript, a function is a value, so we can deal with it as a value. The code above shows its string representation, which is the source code.
+
+Surely, a function is a special value, in the sense that we can call it like `sayHi()`.
+
+But it's still a value. So we can work with it like with other kinds of values.
+
+We can copy a function to another variable:
+
+```js run no-beautify
+function sayHi() { // (1) create
+ alert( "Hello" );
+}
+
+let func = sayHi; // (2) copy
+
+func(); // Hello // (3) run the copy (it works)!
+sayHi(); // Hello // this still works too (why wouldn't it)
+```
+
+Here's what happens above in detail:
+
+1. The Function Declaration `(1)` creates the function and puts it into the variable named `sayHi`.
+2. Line `(2)` copies it into the variable `func`. Please note again: there are no parentheses after `sayHi`. If there were, then `func = sayHi()` would write *the result of the call* `sayHi()` into `func`, not *the function* `sayHi` itself.
+3. Now the function can be called as both `sayHi()` and `func()`.
+
+Note that we could also have used a Function Expression to declare `sayHi`, in the first line:
+
+```js
+let sayHi = function() {
+ alert( "Hello" );
+};
+
+let func = sayHi;
+// ...
+```
+
+Everything would work the same.
+
+
+````smart header="Why is there a semicolon at the end?"
+You might wonder, why does Function Expression have a semicolon `;` at the end, but Function Declaration does not:
+
+```js
+function sayHi() {
+ // ...
+}
+
+let sayHi = function() {
+ // ...
+}*!*;*/!*
+```
+
+The answer is simple:
+- There's no need for `;` at the end of code blocks and syntax structures that use them like `if { ... }`, `for { }`, `function f { }` etc.
+- A Function Expression is used inside the statement: `let sayHi = ...;`, as a value. It's not a code block, but rather an assignment. The semicolon `;` is recommended at the end of statements, no matter what the value is. So the semicolon here is not related to the Function Expression itself, it just terminates the statement.
+````
+
+## Callback functions
+
+Let's look at more examples of passing functions as values and using function expressions.
+
+We'll write a function `ask(question, yes, no)` with three parameters:
+
+`question`
+: Text of the question
+
+`yes`
+: Function to run if the answer is "Yes"
+
+`no`
+: Function to run if the answer is "No"
+
+The function should ask the `question` and, depending on the user's answer, call `yes()` or `no()`:
+
+```js run
+*!*
+function ask(question, yes, no) {
+ if (confirm(question)) yes()
+ else no();
+}
+*/!*
+
+function showOk() {
+ alert( "You agreed." );
+}
+
+function showCancel() {
+ alert( "You canceled the execution." );
+}
+
+// usage: functions showOk, showCancel are passed as arguments to ask
+ask("Do you agree?", showOk, showCancel);
+```
+
+In practice, such functions are quite useful. The major difference between a real-life `ask` and the example above is that real-life functions use more complex ways to interact with the user than a simple `confirm`. In the browser, such function usually draws a nice-looking question window. But that's another story.
+
+**The arguments `showOk` and `showCancel` of `ask` are called *callback functions* or just *callbacks*.**
+
+The idea is that we pass a function and expect it to be "called back" later if necessary. In our case, `showOk` becomes the callback for "yes" answer, and `showCancel` for "no" answer.
+
+We can use Function Expressions to write the same function much shorter:
+
+```js run no-beautify
+function ask(question, yes, no) {
+ if (confirm(question)) yes()
+ else no();
+}
+
+*!*
+ask(
+ "Do you agree?",
+ function() { alert("You agreed."); },
+ function() { alert("You canceled the execution."); }
+);
+*/!*
+```
+
+Here, functions are declared right inside the `ask(...)` call. They have no name, and so are called *anonymous*. Such functions are not accessible outside of `ask` (because they are not assigned to variables), but that's just what we want here.
+
+Such code appears in our scripts very naturally, it's in the spirit of JavaScript.
+
+```smart header="A function is a value representing an \"action\""
+Regular values like strings or numbers represent the *data*.
+
+A function can be perceived as an *action*.
+
+We can pass it between variables and run when we want.
+```
+
+
+## Function Expression vs Function Declaration
+
+Let's formulate the key differences between Function Declarations and Expressions.
+
+First, the syntax: how to differentiate between them in the code.
+
+- *Function Declaration:* a function, declared as a separate statement, in the main code flow.
+
+ ```js
+ // Function Declaration
+ function sum(a, b) {
+ return a + b;
+ }
+ ```
+- *Function Expression:* a function, created inside an expression or inside another syntax construct. Here, the function is created at the right side of the "assignment expression" `=`:
+
+ ```js
+ // Function Expression
+ let sum = function(a, b) {
+ return a + b;
+ };
+ ```
+
+The more subtle difference is *when* a function is created by the JavaScript engine.
+
+**A Function Expression is created when the execution reaches it and is usable only from that moment.**
+
+Once the execution flow passes to the right side of the assignment `let sum = function…` -- here we go, the function is created and can be used (assigned, called, etc. ) from now on.
+
+Function Declarations are different.
+
+**A Function Declaration can be called earlier than it is defined.**
+
+For example, a global Function Declaration is visible in the whole script, no matter where it is.
+
+That's due to internal algorithms. When JavaScript prepares to run the script, it first looks for global Function Declarations in it and creates the functions. We can think of it as an "initialization stage".
+
+And after all Function Declarations are processed, the code is executed. So it has access to these functions.
+
+For example, this works:
+
+```js run refresh untrusted
+*!*
+sayHi("John"); // Hello, John
+*/!*
+
+function sayHi(name) {
+ alert( `Hello, ${name}` );
+}
+```
+
+The Function Declaration `sayHi` is created when JavaScript is preparing to start the script and is visible everywhere in it.
+
+...If it were a Function Expression, then it wouldn't work:
+
+```js run refresh untrusted
+*!*
+sayHi("John"); // error!
+*/!*
+
+let sayHi = function(name) { // (*) no magic any more
+ alert( `Hello, ${name}` );
+};
+```
+
+Function Expressions are created when the execution reaches them. That would happen only in the line `(*)`. Too late.
+
+Another special feature of Function Declarations is their block scope.
+
+**In strict mode, when a Function Declaration is within a code block, it's visible everywhere inside that block. But not outside of it.**
+
+For instance, let's imagine that we need to declare a function `welcome()` depending on the `age` variable that we get during runtime. And then we plan to use it some time later.
+
+If we use Function Declaration, it won't work as intended:
+
+```js run
+let age = prompt("What is your age?", 18);
+
+// conditionally declare a function
+if (age < 18) {
+
+ function welcome() {
+ alert("Hello!");
+ }
+
+} else {
+
+ function welcome() {
+ alert("Greetings!");
+ }
+
+}
+
+// ...use it later
+*!*
+welcome(); // Error: welcome is not defined
+*/!*
+```
+
+That's because a Function Declaration is only visible inside the code block in which it resides.
+
+Here's another example:
+
+```js run
+let age = 16; // take 16 as an example
+
+if (age < 18) {
+*!*
+ welcome(); // \ (runs)
+*/!*
+ // |
+ function welcome() { // |
+ alert("Hello!"); // | Function Declaration is available
+ } // | everywhere in the block where it's declared
+ // |
+*!*
+ welcome(); // / (runs)
+*/!*
+
+} else {
+
+ function welcome() {
+ alert("Greetings!");
+ }
+}
+
+// Here we're out of curly braces,
+// so we can not see Function Declarations made inside of them.
+
+*!*
+welcome(); // Error: welcome is not defined
+*/!*
+```
+
+What can we do to make `welcome` visible outside of `if`?
+
+The correct approach would be to use a Function Expression and assign `welcome` to the variable that is declared outside of `if` and has the proper visibility.
+
+This code works as intended:
+
+```js run
+let age = prompt("What is your age?", 18);
+
+let welcome;
+
+if (age < 18) {
+
+ welcome = function() {
+ alert("Hello!");
+ };
+
+} else {
+
+ welcome = function() {
+ alert("Greetings!");
+ };
+
+}
+
+*!*
+welcome(); // ok now
+*/!*
+```
+
+Or we could simplify it even further using a question mark operator `?`:
+
+```js run
+let age = prompt("What is your age?", 18);
+
+let welcome = (age < 18) ?
+ function() { alert("Hello!"); } :
+ function() { alert("Greetings!"); };
+
+*!*
+welcome(); // ok now
+*/!*
+```
+
+
+```smart header="When to choose Function Declaration versus Function Expression?"
+As a rule of thumb, when we need to declare a function, the first to consider is Function Declaration syntax. It gives more freedom in how to organize our code, because we can call such functions before they are declared.
+
+That's also better for readability, as it's easier to look up `function f(…) {…}` in the code than `let f = function(…) {…};`. Function Declarations are more "eye-catching".
+
+...But if a Function Declaration does not suit us for some reason, or we need a conditional declaration (we've just seen an example), then Function Expression should be used.
+```
+
+## Summary
+
+- Functions are values. They can be assigned, copied or declared in any place of the code.
+- If the function is declared as a separate statement in the main code flow, that's called a "Function Declaration".
+- If the function is created as a part of an expression, it's called a "Function Expression".
+- Function Declarations are processed before the code block is executed. They are visible everywhere in the block.
+- Function Expressions are created when the execution flow reaches them.
+
+In most cases when we need to declare a function, a Function Declaration is preferable, because it is visible prior to the declaration itself. That gives us more flexibility in code organization, and is usually more readable.
+
+So we should use a Function Expression only when a Function Declaration is not fit for the task. We've seen a couple of examples of that in this chapter, and will see more in the future.
diff --git a/1-js/02-first-steps/17-arrow-functions-basics/1-rewrite-arrow/solution.md b/1-js/02-first-steps/17-arrow-functions-basics/1-rewrite-arrow/solution.md
new file mode 100644
index 0000000000..3ea1124739
--- /dev/null
+++ b/1-js/02-first-steps/17-arrow-functions-basics/1-rewrite-arrow/solution.md
@@ -0,0 +1,17 @@
+
+```js run
+function ask(question, yes, no) {
+ if (confirm(question)) yes()
+ else no();
+}
+
+ask(
+ "Do you agree?",
+*!*
+ () => alert("You agreed."),
+ () => alert("You canceled the execution.")
+*/!*
+);
+```
+
+Looks short and clean, right?
diff --git a/1-js/02-first-steps/17-arrow-functions-basics/1-rewrite-arrow/task.md b/1-js/02-first-steps/17-arrow-functions-basics/1-rewrite-arrow/task.md
new file mode 100644
index 0000000000..2f44db27e4
--- /dev/null
+++ b/1-js/02-first-steps/17-arrow-functions-basics/1-rewrite-arrow/task.md
@@ -0,0 +1,17 @@
+
+# Rewrite with arrow functions
+
+Replace Function Expressions with arrow functions in the code below:
+
+```js run
+function ask(question, yes, no) {
+ if (confirm(question)) yes()
+ else no();
+}
+
+ask(
+ "Do you agree?",
+ function() { alert("You agreed."); },
+ function() { alert("You canceled the execution."); }
+);
+```
diff --git a/1-js/02-first-steps/17-arrow-functions-basics/article.md b/1-js/02-first-steps/17-arrow-functions-basics/article.md
new file mode 100644
index 0000000000..e0fb5bda58
--- /dev/null
+++ b/1-js/02-first-steps/17-arrow-functions-basics/article.md
@@ -0,0 +1,111 @@
+# Arrow functions, the basics
+
+There's another very simple and concise syntax for creating functions, that's often better than Function Expressions.
+
+It's called "arrow functions", because it looks like this:
+
+```js
+let func = (arg1, arg2, ...argN) => expression
+```
+
+...This creates a function `func` that accepts arguments `arg1..argN`, then evaluates the `expression` on the right side with their use and returns its result.
+
+In other words, it's the shorter version of:
+
+```js
+let func = function(arg1, arg2, ...argN) {
+ return expression;
+};
+```
+
+Let's see a concrete example:
+
+```js run
+let sum = (a, b) => a + b;
+
+/* This arrow function is a shorter form of:
+
+let sum = function(a, b) {
+ return a + b;
+};
+*/
+
+alert( sum(1, 2) ); // 3
+```
+
+As you can, see `(a, b) => a + b` means a function that accepts two arguments named `a` and `b`. Upon the execution, it evaluates the expression `a + b` and returns the result.
+
+- If we have only one argument, then parentheses around parameters can be omitted, making that even shorter.
+
+ For example:
+
+ ```js run
+ *!*
+ let double = n => n * 2;
+ // roughly the same as: let double = function(n) { return n * 2 }
+ */!*
+
+ alert( double(3) ); // 6
+ ```
+
+- If there are no arguments, parentheses will be empty (but they should be present):
+
+ ```js run
+ let sayHi = () => alert("Hello!");
+
+ sayHi();
+ ```
+
+Arrow functions can be used in the same way as Function Expressions.
+
+For instance, to dynamically create a function:
+
+```js run
+let age = prompt("What is your age?", 18);
+
+let welcome = (age < 18) ?
+ () => alert('Hello') :
+ () => alert("Greetings!");
+
+welcome();
+```
+
+Arrow functions may appear unfamiliar and not very readable at first, but that quickly changes as the eyes get used to the structure.
+
+They are very convenient for simple one-line actions, when we're just too lazy to write many words.
+
+## Multiline arrow functions
+
+The examples above took arguments from the left of `=>` and evaluated the right-side expression with them.
+
+Sometimes we need something a little bit more complex, like multiple expressions or statements. It is also possible, but we should enclose them in curly braces. Then use a normal `return` within them.
+
+Like this:
+
+```js run
+let sum = (a, b) => { // the curly brace opens a multiline function
+ let result = a + b;
+*!*
+ return result; // if we use curly braces, then we need an explicit "return"
+*/!*
+};
+
+alert( sum(1, 2) ); // 3
+```
+
+```smart header="More to come"
+Here we praised arrow functions for brevity. But that's not all!
+
+Arrow functions have other interesting features.
+
+To study them in-depth, we first need to get to know some other aspects of JavaScript, so we'll return to arrow functions later in the chapter .
+
+For now, we can already use arrow functions for one-line actions and callbacks.
+```
+
+## Summary
+
+Arrow functions are handy for one-liners. They come in two flavors:
+
+1. Without curly braces: `(...args) => expression` -- the right side is an expression: the function evaluates it and returns the result.
+2. With curly braces: `(...args) => { body }` -- brackets allow us to write multiple statements inside the function, but we need an explicit `return` to return something.
diff --git a/1-js/02-first-steps/18-javascript-specials/article.md b/1-js/02-first-steps/18-javascript-specials/article.md
new file mode 100644
index 0000000000..91be0aa454
--- /dev/null
+++ b/1-js/02-first-steps/18-javascript-specials/article.md
@@ -0,0 +1,284 @@
+# JavaScript specials
+
+This chapter briefly recaps the features of JavaScript that we've learned by now, paying special attention to subtle moments.
+
+## Code structure
+
+Statements are delimited with a semicolon:
+
+```js run no-beautify
+alert('Hello'); alert('World');
+```
+
+Usually, a line-break is also treated as a delimiter, so that would also work:
+
+```js run no-beautify
+alert('Hello')
+alert('World')
+```
+
+That's called "automatic semicolon insertion". Sometimes it doesn't work, for instance:
+
+```js run
+alert("There will be an error after this message")
+
+[1, 2].forEach(alert)
+```
+
+Most codestyle guides agree that we should put a semicolon after each statement.
+
+Semicolons are not required after code blocks `{...}` and syntax constructs with them like loops:
+
+```js
+function f() {
+ // no semicolon needed after function declaration
+}
+
+for(;;) {
+ // no semicolon needed after the loop
+}
+```
+
+...But even if we can put an "extra" semicolon somewhere, that's not an error. It will be ignored.
+
+More in: .
+
+## Strict mode
+
+To fully enable all features of modern JavaScript, we should start scripts with `"use strict"`.
+
+```js
+'use strict';
+
+...
+```
+
+The directive must be at the top of a script or at the beginning of a function body.
+
+Without `"use strict"`, everything still works, but some features behave in the old-fashion, "compatible" way. We'd generally prefer the modern behavior.
+
+Some modern features of the language (like classes that we'll study in the future) enable strict mode implicitly.
+
+More in: .
+
+## Variables
+
+Can be declared using:
+
+- `let`
+- `const` (constant, can't be changed)
+- `var` (old-style, will see later)
+
+A variable name can include:
+- Letters and digits, but the first character may not be a digit.
+- Characters `$` and `_` are normal, on par with letters.
+- Non-Latin alphabets and hieroglyphs are also allowed, but commonly not used.
+
+Variables are dynamically typed. They can store any value:
+
+```js
+let x = 5;
+x = "John";
+```
+
+There are 8 data types:
+
+- `number` for both floating-point and integer numbers,
+- `bigint` for integer numbers of arbitrary length,
+- `string` for strings,
+- `boolean` for logical values: `true/false`,
+- `null` -- a type with a single value `null`, meaning "empty" or "does not exist",
+- `undefined` -- a type with a single value `undefined`, meaning "not assigned",
+- `object` and `symbol` -- for complex data structures and unique identifiers, we haven't learnt them yet.
+
+The `typeof` operator returns the type for a value, with two exceptions:
+```js
+typeof null == "object" // error in the language
+typeof function(){} == "function" // functions are treated specially
+```
+
+More in: and .
+
+## Interaction
+
+We're using a browser as a working environment, so basic UI functions will be:
+
+[`prompt(question, [default])`](mdn:api/Window/prompt)
+: Ask a `question`, and return either what the visitor entered or `null` if they clicked "cancel".
+
+[`confirm(question)`](mdn:api/Window/confirm)
+: Ask a `question` and suggest to choose between Ok and Cancel. The choice is returned as `true/false`.
+
+[`alert(message)`](mdn:api/Window/alert)
+: Output a `message`.
+
+All these functions are *modal*, they pause the code execution and prevent the visitor from interacting with the page until they answer.
+
+For instance:
+
+```js run
+let userName = prompt("Your name?", "Alice");
+let isTeaWanted = confirm("Do you want some tea?");
+
+alert( "Visitor: " + userName ); // Alice
+alert( "Tea wanted: " + isTeaWanted ); // true
+```
+
+More in: .
+
+## Operators
+
+JavaScript supports the following operators:
+
+Arithmetical
+: Regular: `* + - /`, also `%` for the remainder and `**` for power of a number.
+
+ The binary plus `+` concatenates strings. And if any of the operands is a string, the other one is converted to string too:
+
+ ```js run
+ alert( '1' + 2 ); // '12', string
+ alert( 1 + '2' ); // '12', string
+ ```
+
+Assignments
+: There is a simple assignment: `a = b` and combined ones like `a *= 2`.
+
+Bitwise
+: Bitwise operators work with 32-bit integers at the lowest, bit-level: see the [docs](mdn:/JavaScript/Reference/Operators/Bitwise_Operators) when they are needed.
+
+Conditional
+: The only operator with three parameters: `cond ? resultA : resultB`. If `cond` is truthy, returns `resultA`, otherwise `resultB`.
+
+Logical operators
+: Logical AND `&&` and OR `||` perform short-circuit evaluation and then return the value where it stopped (not necessary `true`/`false`). Logical NOT `!` converts the operand to boolean type and returns the inverse value.
+
+Nullish coalescing operator
+: The `??` operator provides a way to choose a defined value from a list of variables. The result of `a ?? b` is `a` unless it's `null/undefined`, then `b`.
+
+Comparisons
+: Equality check `==` for values of different types converts them to a number (except `null` and `undefined` that equal each other and nothing else), so these are equal:
+
+ ```js run
+ alert( 0 == false ); // true
+ alert( 0 == '' ); // true
+ ```
+
+ Other comparisons convert to a number as well.
+
+ The strict equality operator `===` doesn't do the conversion: different types always mean different values for it.
+
+ Values `null` and `undefined` are special: they equal `==` each other and don't equal anything else.
+
+ Greater/less comparisons compare strings character-by-character, other types are converted to a number.
+
+Other operators
+: There are few others, like a comma operator.
+
+More in: , , , .
+
+## Loops
+
+- We covered 3 types of loops:
+
+ ```js
+ // 1
+ while (condition) {
+ ...
+ }
+
+ // 2
+ do {
+ ...
+ } while (condition);
+
+ // 3
+ for(let i = 0; i < 10; i++) {
+ ...
+ }
+ ```
+
+- The variable declared in `for(let...)` loop is visible only inside the loop. But we can also omit `let` and reuse an existing variable.
+- Directives `break/continue` allow to exit the whole loop/current iteration. Use labels to break nested loops.
+
+Details in: .
+
+Later we'll study more types of loops to deal with objects.
+
+## The "switch" construct
+
+The "switch" construct can replace multiple `if` checks. It uses `===` (strict equality) for comparisons.
+
+For instance:
+
+```js run
+let age = prompt('Your age?', 18);
+
+switch (age) {
+ case 18:
+ alert("Won't work"); // the result of prompt is a string, not a number
+ break;
+
+ case "18":
+ alert("This works!");
+ break;
+
+ default:
+ alert("Any value not equal to one above");
+}
+```
+
+Details in: .
+
+## Functions
+
+We covered three ways to create a function in JavaScript:
+
+1. Function Declaration: the function in the main code flow
+
+ ```js
+ function sum(a, b) {
+ let result = a + b;
+
+ return result;
+ }
+ ```
+
+2. Function Expression: the function in the context of an expression
+
+ ```js
+ let sum = function(a, b) {
+ let result = a + b;
+
+ return result;
+ };
+ ```
+
+3. Arrow functions:
+
+ ```js
+ // expression at the right side
+ let sum = (a, b) => a + b;
+
+ // or multi-line syntax with { ... }, need return here:
+ let sum = (a, b) => {
+ // ...
+ return a + b;
+ }
+
+ // without arguments
+ let sayHi = () => alert("Hello");
+
+ // with a single argument
+ let double = n => n * 2;
+ ```
+
+
+- Functions may have local variables: those declared inside its body. Such variables are only visible inside the function.
+- Parameters can have default values: `function sum(a = 1, b = 2) {...}`.
+- Functions always return something. If there's no `return` statement, then the result is `undefined`.
+
+Details: see , .
+
+## More to come
+
+That was a brief list of JavaScript features. As of now we've studied only basics. Further in the tutorial you'll find more specials and advanced features of JavaScript.
diff --git a/1-js/03-code-quality/01-debugging-chrome/article.md b/1-js/03-code-quality/01-debugging-chrome/article.md
index 16ee7fa48d..8132ca1e2d 100644
--- a/1-js/03-code-quality/01-debugging-chrome/article.md
+++ b/1-js/03-code-quality/01-debugging-chrome/article.md
@@ -4,7 +4,11 @@
[Отладка](https://ru.wikipedia.org/wiki/%D0%9E%D1%82%D0%BB%D0%B0%D0%B4%D0%BA%D0%B0_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D1%8B) - это процесс поиска и исправления ошибок в скрипте. Все современные браузеры и большинство других сред разработки поддерживают инструменты для отладки - специальный графический интерфейс, который сильно упрощает отладку. Он также позволяет по шагам отследить, что именно происходит в нашем коде.
+<<<<<<< HEAD
Мы будем использовать браузер Chrome, так как у него достаточно возможностей, в большинстве других браузеров процесс будет схожим.
+=======
+We'll be using Chrome here, because it has enough features, most other browsers have a similar process.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
## Панель "Исходный код" ("Sources")
@@ -18,12 +22,17 @@

+<<<<<<< HEAD
Кнопка-переключатель откроет вкладку со списком файлов.
+=======
+The toggler button opens the tab with files.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Кликните на неё и выберите `hello.js`. Вот что появится:

+<<<<<<< HEAD
Интерфейс состоит из трёх зон:
1. В зоне **Resources** (Ресурсы) показаны файлы HTML, JavaScript, CSS, включая изображения, используемые на странице. Здесь также могут быть файлы различных расширений Chrome.
@@ -31,6 +40,15 @@
3. Наконец, зона **Information and control** (Сведения и контроль) отведена для отладки, вскоре мы к ней вернёмся.
Чтобы скрыть список ресурсов и освободить экранное место для исходного кода, щёлкните по тому же переключателю .
+=======
+The Sources panel has 3 parts:
+
+1. The **File Navigator** pane lists HTML, JavaScript, CSS and other files, including images that are attached to the page. Chrome extensions may appear here too.
+2. The **Code Editor** pane shows the source code.
+3. The **JavaScript Debugging** pane is for debugging, we'll explore it soon.
+
+Now you could click the same toggler again to hide the resources list and give the code some space.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
## Консоль
@@ -120,10 +138,17 @@ function hello(name) {
А теперь давайте *пошагаем* по нашему коду.
+<<<<<<< HEAD
В правой части панели для этого есть несколько кнопок. Рассмотрим их.
– продолжить выполнение. Быстрая клавиша – `key:F8`.
: Возобновляет выполнение кода. Если больше нет точек останова, отладчик прекращает работу и позволяет приложению работать дальше.
+=======
+There are buttons for it at the top of the right panel. Let's engage them.
+
+ -- "Resume": continue the execution, hotkey `key:F8`.
+: Resumes the execution. If there are no additional breakpoints, then the execution just continues and the debugger loses control.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Вот, что мы увидим, кликнув на неё:
@@ -131,6 +156,7 @@ function hello(name) {
Выполнение кода возобновилось, дошло до другой точки останова внутри `say()`, и отладчик снова приостановил выполнение. Обратите внимание на пункт "Call stack" справа: в списке появился ещё один вызов. Мы теперь внутри функции `say()`.
+<<<<<<< HEAD
– сделать шаг (выполнить следующую команду), *не заходя в функцию*. Быстрая клавиша – `key:F10`.
: Если мы нажмём на неё - будет вызван `alert`. Важно: на месте `alert` может быть любая другая функция, выполнение просто *перешагнёт через неё*, полностью игнорируя её содержимое.
@@ -145,6 +171,35 @@ function hello(name) {
– разрешить/запретить остановку выполнения в случае возникновения ошибки.
: Если опция включена и инструменты разработчика открыты, любая ошибка в скрипте приостанавливает выполнение кода, что позволяет его проанализировать. Поэтому если скрипт завершается с ошибкой, открываем отладчик, включаем эту опцию, перезагружаем страницу и локализуем проблему.
+=======
+ -- "Step": run the next command, hotkey `key:F9`.
+: Run the next statement. If we click it now, `alert` will be shown.
+
+ Clicking this again and again will step through all script statements one by one.
+
+ -- "Step over": run the next command, but *don't go into a function*, hotkey `key:F10`.
+: Similar to the previous the "Step" command, but behaves differently if the next statement is a function call. That is: not a built-in, like `alert`, but a function of our own.
+
+ The "Step" command goes into it and pauses the execution at its first line, while "Step over" executes the nested function call invisibly, skipping the function internals.
+
+ The execution is then paused immediately after that function.
+
+ That's good if we're not interested to see what happens inside the function call.
+
+ -- "Step into", hotkey `key:F11`.
+: That's similar to "Step", but behaves differently in case of asynchronous function calls. If you're only starting to learn JavaScript, then you can ignore the difference, as we don't have asynchronous calls yet.
+
+ For the future, just note that "Step" command ignores async actions, such as `setTimeout` (scheduled function call), that execute later. The "Step into" goes into their code, waiting for them if necessary. See [DevTools manual](https://developers.google.com/web/updates/2018/01/devtools#async) for more details.
+
+ -- "Step out": continue the execution till the end of the current function, hotkey `key:Shift+F11`.
+: Continue the execution and stop it at the very last line of the current function. That's handy when we accidentally entered a nested call using , but it does not interest us, and we want to continue to its end as soon as possible.
+
+ -- enable/disable all breakpoints.
+: That button does not move the execution. Just a mass on/off for breakpoints.
+
+ -- enable/disable automatic pause in case of an error.
+: When enabled, and the developer tools is open, a script error automatically pauses the execution. Then we can analyze variables to see what went wrong. So if our script dies with an error, we can open debugger, enable this option and reload the page to see where it dies and what's the context at that moment.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```smart header="Continue to here"
Если щёлкнуть правой кнопкой мыши по строчке кода, в контекстном меню можно выбрать опцию "Continue to here" ("продолжить до этого места").
@@ -173,9 +228,16 @@ for (let i = 0; i < 5; i++) {
Приостановить выполнение скрипта можно тремя способами:
+<<<<<<< HEAD
1. Точками останова.
2. Использованием в коде команды `debugger`.
3. При ошибке (если инструменты разработчика открыты и опция включена).
+=======
+As we can see, there are three main ways to pause a script:
+1. A breakpoint.
+2. The `debugger` statements.
+3. An error (if dev tools are open and the button is "on").
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
При остановке мы можем отлаживать - проанализировать переменные и пошагово пройти по процессу, что поможет отыскать проблему.
diff --git a/1-js/03-code-quality/01-debugging-chrome/head.html b/1-js/03-code-quality/01-debugging-chrome/head.html
index f219b0af18..615326c08e 100644
--- a/1-js/03-code-quality/01-debugging-chrome/head.html
+++ b/1-js/03-code-quality/01-debugging-chrome/head.html
@@ -1,8 +1,8 @@
diff --git a/1-js/03-code-quality/01-debugging-chrome/largeIcons.svg b/1-js/03-code-quality/01-debugging-chrome/largeIcons.svg
new file mode 100644
index 0000000000..83303365bd
--- /dev/null
+++ b/1-js/03-code-quality/01-debugging-chrome/largeIcons.svg
@@ -0,0 +1,1472 @@
+
+
diff --git a/1-js/03-code-quality/01-debugging-chrome/toolbarButtonGlyphs.svg b/1-js/03-code-quality/01-debugging-chrome/toolbarButtonGlyphs.svg
deleted file mode 100644
index 5bdf20a83a..0000000000
--- a/1-js/03-code-quality/01-debugging-chrome/toolbarButtonGlyphs.svg
+++ /dev/null
@@ -1,1035 +0,0 @@
-
-
\ No newline at end of file
diff --git a/1-js/03-code-quality/02-coding-style/1-style-errors/solution.md b/1-js/03-code-quality/02-coding-style/1-style-errors/solution.md
index 84126c3a96..45853de442 100644
--- a/1-js/03-code-quality/02-coding-style/1-style-errors/solution.md
+++ b/1-js/03-code-quality/02-coding-style/1-style-errors/solution.md
@@ -10,12 +10,21 @@ function pow(x,n) // <- отсутствует пробел между аргу
return result;
}
+<<<<<<< HEAD
let x=prompt("x?",''), n=prompt("n?",'') // <-- технически допустимо,
// но лучше написать в 2 строки, также нет пробелов и точки с запятой
if (n<0) // <- нет пробелов, стоит добавить отступ в одну строку сверху
{ // <- фигурная скобка на отдельной строке
// ниже - слишком длинная строка, лучше разбить для улучшения читаемости
alert(`Степень ${n} не поддерживается, введите целую степень, большую 0`);
+=======
+let x=prompt("x?",''), n=prompt("n?",'') // <-- technically possible,
+// but better make it 2 lines, also there's no spaces and missing ;
+if (n<=0) // <- no spaces inside (n <= 0), and should be extra line above it
+{ // <- figure bracket on a separate line
+ // below - long lines can be split into multiple lines for improved readability
+ alert(`Power ${n} is not supported, please enter an integer number greater than zero`);
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
}
else // <- можно на одной строке, вместе: "} else {"
{
@@ -39,9 +48,15 @@ function pow(x, n) {
let x = prompt("x?", "");
let n = prompt("n?", "");
+<<<<<<< HEAD
if (n < 0) {
alert(`Степень ${n} не поддерживается,
введите целую степень, большую 0`);
+=======
+if (n <= 0) {
+ alert(`Power ${n} is not supported,
+ please enter an integer number greater than zero`);
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
} else {
alert( pow(x, n) );
}
diff --git a/1-js/03-code-quality/02-coding-style/article.md b/1-js/03-code-quality/02-coding-style/article.md
index 5b5be39c22..f1fa49ed61 100644
--- a/1-js/03-code-quality/02-coding-style/article.md
+++ b/1-js/03-code-quality/02-coding-style/article.md
@@ -85,9 +85,15 @@ if (condition) {
```js
// обратные кавычки ` позволяют разделять строку на части
let str = `
+<<<<<<< HEAD
Рабочая группа TC39 организации Ecma International -
это группа JavaScript-разработчиков, теоретиков и авторов движков JavaScript,
которые вместе с сообществом занимаются поддержкой и развитием языка JavaScript.
+=======
+ ECMA International's TC39 is a group of JavaScript developers,
+ implementers, academics, and more, collaborating with the community
+ to maintain and evolve the definition of JavaScript.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
`;
```
@@ -284,9 +290,15 @@ function pow(x, n) {
Некоторые популярные руководства:
+<<<<<<< HEAD
- [Google JavaScript Style Guide](https://google.github.io/styleguide/javascriptguide.xml)
- [Airbnb JavaScript Style Guide](https://github.com/airbnb/javascript) (есть [перевод](https://leonidlebedev.github.io/javascript-airbnb/))
- [Idiomatic.JS](https://github.com/rwaldron/idiomatic.js) (есть [перевод](https://github.com/rwaldron/idiomatic.js/tree/master/translations/ru_RU))
+=======
+- [Google JavaScript Style Guide](https://google.github.io/styleguide/jsguide.html)
+- [Airbnb JavaScript Style Guide](https://github.com/airbnb/javascript)
+- [Idiomatic.JS](https://github.com/rwaldron/idiomatic.js)
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
- [StandardJS](https://standardjs.com/)
- (и ещё множество других)
diff --git a/1-js/03-code-quality/03-comments/article.md b/1-js/03-code-quality/03-comments/article.md
index 749d18fae5..6e7441d312 100644
--- a/1-js/03-code-quality/03-comments/article.md
+++ b/1-js/03-code-quality/03-comments/article.md
@@ -125,6 +125,7 @@ function addJuice(container) {
Документируйте параметры и использование функций
: Есть специальный синтаксис [JSDoc](https://ru.wikipedia.org/wiki/JSDoc) для документирования функций: использование, параметры, возвращаемое значение.
+<<<<<<< HEAD
Например:
```js
/**
@@ -144,6 +145,27 @@ function addJuice(container) {
Кстати, многие редакторы, такие как [WebStorm](https://www.jetbrains.com/webstorm/), прекрасно их распознают для того, чтобы выполнить автодополнение ввода и различные автоматические проверки кода.
Также существуют инструменты, например, [JSDoc 3](https://github.com/jsdoc3/jsdoc), которые умеют генерировать HTML-документацию из комментариев. Получить больше информации о JSDoc вы можете здесь: .
+=======
+For instance:
+```js
+/**
+ * Returns x raised to the n-th power.
+ *
+ * @param {number} x The number to raise.
+ * @param {number} n The power, must be a natural number.
+ * @return {number} x raised to the n-th power.
+ */
+function pow(x, n) {
+ ...
+}
+```
+
+Such comments allow us to understand the purpose of the function and use it the right way without looking in its code.
+
+By the way, many editors like [WebStorm](https://www.jetbrains.com/webstorm/) can understand them as well and use them to provide autocomplete and some automatic code-checking.
+
+Also, there are tools like [JSDoc 3](https://github.com/jsdoc3/jsdoc) that can generate HTML-documentation from the comments. You can read more information about JSDoc at .
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Почему задача решена именно таким способом?
: Важно то, что написано. Но то, что *не* написано, может быть даже более важным, чтобы понимать происходящее. Почему задача решена именно этим способом? Код не даёт ответа.
diff --git a/1-js/03-code-quality/04-ninja-code/article.md b/1-js/03-code-quality/04-ninja-code/article.md
index f220e00859..4a64be4fd5 100644
--- a/1-js/03-code-quality/04-ninja-code/article.md
+++ b/1-js/03-code-quality/04-ninja-code/article.md
@@ -35,7 +35,11 @@ i = i ? i < 0 ? Math.max(0, len + i) : i : 0;
Кто знает — не говорит. Кто говорит — не знает.
```
+<<<<<<< HEAD
Ещё один способ писать быстрее - использовать короткие имена переменных. Называйте их `a`, `b` или `c`.
+=======
+Another way to code shorter is to use single-letter variable names everywhere. Like `a`, `b` or `c`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Короткая переменная прячется в коде лучше, чем ниндзя в лесу. Никто не сможет найти её, используя функцию "Поиск" текстового редактора. Более того, даже найдя – никто не сможет "расшифровать" её и догадаться, что она означает.
diff --git a/1-js/03-code-quality/05-testing-mocha/article.md b/1-js/03-code-quality/05-testing-mocha/article.md
index 289c864954..c35bfb8ab4 100644
--- a/1-js/03-code-quality/05-testing-mocha/article.md
+++ b/1-js/03-code-quality/05-testing-mocha/article.md
@@ -79,7 +79,11 @@ describe("pow", function() {
Давайте посмотрим этот поток разработки на нашем примере.
+<<<<<<< HEAD
Первый шаг уже завершён. У нас есть спецификация для функции `pow`. Теперь, перед тем, как писать реализацию, давайте подключим библиотеки для пробного запуска тестов, просто чтобы убедиться, что тесты работают (разумеется, они завершатся ошибками).
+=======
+The first step is already complete: we have an initial spec for `pow`. Now, before making the implementation, let's use few JavaScript libraries to run the tests, just to see that they are working (they will all fail).
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
## Спецификация в действии
@@ -160,7 +164,11 @@ function pow(x, n) {
assert.equal(pow(2, 3), 8);
});
+<<<<<<< HEAD
it("3 в степени 4 будет 81", function() {
+=======
+ it("3 raised to power 4 is 81", function() {
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
assert.equal(pow(3, 4), 81);
});
@@ -183,7 +191,11 @@ function pow(x, n) {
[iframe height=250 src="pow-2" edit border="1"]
+<<<<<<< HEAD
Как мы и ожидали, второй тест провалился. Естественно, наша функция всегда возвращает `8`, в то время как `assert` ожидает `81`.
+=======
+As we could expect, the second test failed. Sure, our function always returns `8`, while the `assert` expects `81`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
## Улучшаем реализацию
diff --git a/1-js/03-code-quality/05-testing-mocha/beforeafter.view/test.js b/1-js/03-code-quality/05-testing-mocha/beforeafter.view/test.js
index 2116ec3b01..23a04cb323 100644
--- a/1-js/03-code-quality/05-testing-mocha/beforeafter.view/test.js
+++ b/1-js/03-code-quality/05-testing-mocha/beforeafter.view/test.js
@@ -1,7 +1,20 @@
+<<<<<<< HEAD
describe("тест", function () {
before(() => alert("Тестирование началось – перед тестами"));
after(() => alert("Тестирование закончилось – после всех тестов"));
+=======
+describe("test", function() {
+
+ // Mocha usually waits for the tests for 2 seconds before considering them wrong
+
+ this.timeout(200000); // With this code we increase this - in this case to 200,000 milliseconds
+
+ // This is because of the "alert" function, because if you delay pressing the "OK" button the tests will not pass!
+
+ before(() => alert("Testing started – before all tests"));
+ after(() => alert("Testing finished – after all tests"));
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
beforeEach(() => alert("Перед тестом – начинаем выполнять тест"));
afterEach(() => alert("После теста – заканчиваем выполнение теста"));
diff --git a/1-js/03-code-quality/05-testing-mocha/pow-2.view/test.js b/1-js/03-code-quality/05-testing-mocha/pow-2.view/test.js
index 6df4aabed4..57d679922a 100644
--- a/1-js/03-code-quality/05-testing-mocha/pow-2.view/test.js
+++ b/1-js/03-code-quality/05-testing-mocha/pow-2.view/test.js
@@ -4,8 +4,13 @@ describe("pow", function() {
assert.equal(pow(2, 3), 8);
});
+<<<<<<< HEAD
it("3 в степени 3 будет 27", function () {
assert.equal(pow(3, 3), 27);
+=======
+ it("3 raised to power 4 is 81", function() {
+ assert.equal(pow(3, 4), 81);
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
});
});
diff --git a/1-js/03-code-quality/06-polyfills/article.md b/1-js/03-code-quality/06-polyfills/article.md
index 9be2b3eb6b..e4b8912466 100644
--- a/1-js/03-code-quality/06-polyfills/article.md
+++ b/1-js/03-code-quality/06-polyfills/article.md
@@ -19,7 +19,11 @@ JavaScript - динамично развивающийся язык програ
На самом деле, есть две части Babel:
+<<<<<<< HEAD
1. Во-первых, транспилер, который переписывает код. Разработчик запускает Babel на своём компьютере. Он переписывает код в старый стандарт. И после этого код отправляется на сайт. Современные сборщики проектов, такие как [webpack](http://webpack.github.io/) или [brunch](http://brunch.io/), предоставляют возможность запускать транспилер автоматически после каждого изменения кода, что позволяет экономить время.
+=======
+1. First, the transpiler program, which rewrites the code. The developer runs it on their own computer. It rewrites the code into the older standard. And then the code is delivered to the website for users. Modern project build systems like [webpack](http://webpack.github.io/) provide means to run transpiler automatically on every code change, so that it's very easy to integrate into development process.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
2. Во-вторых, полифил.
diff --git a/1-js/04-object-basics/01-object/article.md b/1-js/04-object-basics/01-object/article.md
index 53cfb3ab8e..1616c38bc6 100644
--- a/1-js/04-object-basics/01-object/article.md
+++ b/1-js/04-object-basics/01-object/article.md
@@ -1,7 +1,11 @@
# Объекты
+<<<<<<< HEAD
Как мы знаем из главы , в JavaScript существует 8 типов данных. Семь из них называются "примитивными", так как содержат только одно значение (будь то строка, число или что-то другое).
+=======
+As we know from the chapter , there are eight data types in JavaScript. Seven of them are called "primitive", because their values contain only a single thing (be it a string or a number or whatever).
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Объекты же используются для хранения коллекций различных значений и более сложных сущностей. В JavaScript объекты используются очень часто, это одна из основ языка. Поэтому мы должны понять их, прежде чем углубляться куда-либо ещё.
@@ -94,7 +98,35 @@ let user = {
```
Это называется "висячая запятая". Такой подход упрощает добавление, удаление и перемещение свойств, так как все строки объекта становятся одинаковыми.
+<<<<<<< HEAD
## Квадратные скобки
+=======
+````smart header="Object with const can be changed"
+Please note: an object declared as `const` *can* be modified.
+
+For instance:
+
+```js run
+const user = {
+ name: "John"
+};
+
+*!*
+user.name = "Pete"; // (*)
+*/!*
+
+alert(user.name); // Pete
+```
+
+It might seem that the line `(*)` would cause an error, but no. The `const` fixes the value of `user`, but not its contents.
+
+The `const` would give an error only if we try to set `user=...` as a whole.
+
+There's another way to make constant object properties, we'll cover it later in the chapter .
+````
+
+## Square brackets
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Для свойств, имена которых состоят из нескольких слов, доступ к значению "через точку" не работает:
@@ -103,9 +135,15 @@ let user = {
user.likes birds = true
```
+<<<<<<< HEAD
JavaScript видит, что мы обращаемся к свойству `user.likes`, а затем идёт непонятное слово `birds`. В итоге синтаксическая ошибка.
Точка требует, чтобы ключ был именован по правилам именования переменных. То есть не имел пробелов, не начинался с цифры и не содержал специальные символы, кроме `$` и `_`.
+=======
+JavaScript doesn't understand that. It thinks that we address `user.likes`, and then gives a syntax error when comes across unexpected `birds`.
+
+The dot requires the key to be a valid variable identifier. That implies: contains no spaces, doesn't start with a digit and doesn't include special characters (`$` and `_` are allowed).
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Для таких случаев существует альтернативный способ доступа к свойствам через квадратные скобки. Такой способ сработает с любым именем свойства:
@@ -166,7 +204,11 @@ alert( user.key ); // undefined
### Вычисляемые свойства
+<<<<<<< HEAD
Мы можем использовать квадратные скобки в литеральной нотации для создания *вычисляемого свойства*.
+=======
+We can use square brackets in an object literal, when creating an object. That's called *computed properties*.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Пример:
@@ -208,6 +250,7 @@ let bag = {
Квадратные скобки дают намного больше возможностей, чем запись через точку. Они позволяют использовать любые имена свойств и переменные, хотя и требуют более громоздких конструкций кода.
+<<<<<<< HEAD
Подведём итог: в большинстве случаев, когда имена свойств известны и просты, используется запись через точку. Если же нам нужно что-то более сложное, то мы используем квадратные скобки.
## Свойство из переменной
@@ -215,13 +258,25 @@ let bag = {
В реальном коде часто нам необходимо использовать существующие переменные как значения для свойств с тем же именем.
Например:
+=======
+## Property value shorthand
+
+In real code we often use existing variables as values for property names.
+
+For instance:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js run
function makeUser(name, age) {
return {
name: name,
+<<<<<<< HEAD
age: age
// ...другие свойства
+=======
+ age: age,
+ // ...other properties
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
};
}
@@ -237,8 +292,13 @@ alert(user.name); // John
function makeUser(name, age) {
*!*
return {
+<<<<<<< HEAD
name, // то же самое, что и name: name
age // то же самое, что и age: age
+=======
+ name, // same as name: name
+ age, // same as age: age
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
// ...
};
*/!*
@@ -254,6 +314,7 @@ let user = {
};
```
+<<<<<<< HEAD
## Ограничения на имена свойств
Мы можем использовать только строки и символы в качестве ключей свойств. Все другие типы данных будут автоматически преобразованы к строке.
@@ -277,6 +338,17 @@ alert( obj[0] ); // Тест (то же свойство)
Но для свойств объекта такого ограничения нет:
```js run
+=======
+
+## Property names limitations
+
+As we already know, a variable cannot have a name equal to one of language-reserved words like "for", "let", "return" etc.
+
+But for an object property, there's no such restriction:
+
+```js run
+// these properties are all right
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
let obj = {
for: 1,
let: 2,
@@ -286,6 +358,7 @@ let obj = {
alert( obj.for + obj.let + obj.return ); // 6
```
+<<<<<<< HEAD
**В принципе, разрешены любые имена свойств, но есть специальное свойство `__proto__`, которое по историческим причинам имеет особое поведение.**
Например, его значение всегда должно быть объектом:
@@ -311,6 +384,41 @@ alert(obj.__proto__); // [object Object], работает не так, как
## Проверка существования свойства, оператор "in"
Особенность объектов в том, что можно получить доступ к любому свойству. Даже если свойства не существует - ошибки не будет! При обращении к свойству, которого нет, возвращается `undefined`. Это позволяет просто проверить существование свойства - сравнением его с `undefined`:
+=======
+In short, there are no limitations on property names. They can be any strings or symbols (a special type for identifiers, to be covered later).
+
+Other types are automatically converted to strings.
+
+For instance, a number `0` becomes a string `"0"` when used as a property key:
+
+```js run
+let obj = {
+ 0: "test" // same as "0": "test"
+};
+
+// both alerts access the same property (the number 0 is converted to string "0")
+alert( obj["0"] ); // test
+alert( obj[0] ); // test (same property)
+```
+
+There's a minor gotcha with a special property named `__proto__`. We can't set it to a non-object value:
+
+```js run
+let obj = {};
+obj.__proto__ = 5; // assign a number
+alert(obj.__proto__); // [object Object] - the value is an object, didn't work as intended
+```
+
+As we see from the code, the assignment to a primitive `5` is ignored.
+
+We'll cover the special nature of `__proto__` in [subsequent chapters](info:prototype-inheritance), and suggest the [ways to fix](info:prototype-methods) such behavior.
+
+## Property existence test, "in" operator
+
+A notable feature of objects in JavaScript, compared to many other languages, is that it's possible to access any property. There will be no error if the property doesn't exist!
+
+Reading a non-existing property just returns `undefined`. So we can easily test whether the property exists:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js run
let user = {};
@@ -318,7 +426,11 @@ let user = {};
alert( user.noSuchProperty === undefined ); // true означает "свойства нет"
```
+<<<<<<< HEAD
Также существует специальный оператор `"in"` для проверки существования свойства в объекте.
+=======
+There's also a special operator `"in"` for that.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Синтаксис оператора:
```js
@@ -336,17 +448,30 @@ alert( "blabla" in user ); // false, user.blabla не существует
Обратите внимание, что слева от оператора `in` должно быть *имя свойства*. Обычно это строка в кавычках.
+<<<<<<< HEAD
Если мы опускаем кавычки, это значит, что мы указываем переменную, в которой находится имя свойства. Например:
+=======
+If we omit quotes, that means a variable, it should contain the actual name to be tested. For instance:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js run
let user = { age: 30 };
let key = "age";
+<<<<<<< HEAD
alert( *!*key*/!* in user ); // true, имя свойства было взято из переменной key
```
````smart header="Оператор \"in\" для свойств со значением *'undefined'*"
Обычно строгого сравнения `"=== undefined"` достаточно для проверки наличия свойства. Но есть особый случай, когда оно не подходит, и нужно использовать `"in"`.
+=======
+alert( *!*key*/!* in user ); // true, property "age" exists
+```
+
+Why does the `in` operator exist? Isn't it enough to compare against `undefined`?
+
+Well, most of the time the comparison with `undefined` works fine. But there's a special case when it fails, but `"in"` works correctly.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Это когда свойство существует, но содержит значение `undefined`:
@@ -360,12 +485,19 @@ alert( obj.test ); // выведет undefined, значит свойство н
alert( "test" in obj ); // true, свойство существует!
```
+<<<<<<< HEAD
В примере выше свойство `obj.test` технически существует в объекте. Оператор `in` сработал правильно.
Подобные ситуации случаются очень редко, так как `undefined` обычно явно не присваивается. Для "неизвестных" или "пустых" свойств мы используем значение `null`. Таким образом, оператор `in` является экзотическим гостем в коде.
````
+=======
+In the code above, the property `obj.test` technically exists. So the `in` operator works right.
+
+Situations like this happen very rarely, because `undefined` should not be explicitly assigned. We mostly use `null` for "unknown" or "empty" values. So the `in` operator is an exotic guest in the code.
+
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
## Цикл "for..in"
@@ -402,8 +534,12 @@ for (let key in user) {
Кроме того, мы могли бы использовать другое имя переменной. Например, часто используется вариант `"for (let prop in obj)"`.
+<<<<<<< HEAD
### Упорядочение свойств объекта
+=======
+### Ordered like an object
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Упорядочены ли свойства объекта? Другими словами, если мы будем в цикле перебирать все свойства объекта, получим ли мы их в том же порядке, в котором мы их добавляли? Можем ли мы на это рассчитывать?
@@ -486,6 +622,7 @@ for (let code in codes) {
Теперь код работает так, как мы задумывали.
+<<<<<<< HEAD
## Копирование по ссылке
Одним из фундаментальных отличий объектов от примитивных типов данных является то, что они хранятся и копируются "по ссылке".
@@ -751,6 +888,9 @@ alert(clone.sizes.width); // 51, видим результат в другом
## Итого
Объекты - это ассоциативные массивы с рядом дополнительных возможностей.
+=======
+## Summary
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Они хранят свойства (пары ключ-значение), где:
- Ключи свойств должны быть строками или символами (обычно строками).
@@ -766,11 +906,15 @@ alert(clone.sizes.width); // 51, видим результат в другом
- Проверка существования свойства: `"key" in obj`.
- Перебор свойств объекта: цикл for `for (let key in obj)`.
+<<<<<<< HEAD
Объекты присваиваются и копируются по ссылке. Другими словами, переменная хранит не "значение объекта", а "ссылку" (адрес в памяти) на это значение. Поэтому копирование такой переменной или передача её в качестве аргумента функции приводит к копированию этой ссылки, а не самого объекта. Все операции с использованием скопированных ссылок (например, добавление или удаление свойств) выполняются с одним и тем же объектом.
Чтобы сделать "настоящую копию" (клон), мы можем использовать `Object.assign` или [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep).
То, что мы изучали в этой главе, называется "простым объектом" ("plain object") или просто `Object`.
+=======
+What we've studied in this chapter is called a "plain object", or just `Object`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
В JavaScript есть много других типов объектов:
diff --git a/1-js/04-object-basics/02-object-copy/article.md b/1-js/04-object-basics/02-object-copy/article.md
new file mode 100644
index 0000000000..c888722326
--- /dev/null
+++ b/1-js/04-object-basics/02-object-copy/article.md
@@ -0,0 +1,228 @@
+# Object copying, references
+
+One of the fundamental differences of objects vs primitives is that they are stored and copied "by reference".
+
+Primitive values: strings, numbers, booleans -- are assigned/copied "as a whole value".
+
+For instance:
+
+```js
+let message = "Hello!";
+let phrase = message;
+```
+
+As a result we have two independent variables, each one is storing the string `"Hello!"`.
+
+
+
+Objects are not like that.
+
+**A variable stores not the object itself, but its "address in memory", in other words "a reference" to it.**
+
+Here's the picture for the object:
+
+```js
+let user = {
+ name: "John"
+};
+```
+
+
+
+Here, the object is stored somewhere in memory. And the variable `user` has a "reference" to it.
+
+**When an object variable is copied -- the reference is copied, the object is not duplicated.**
+
+For instance:
+
+```js no-beautify
+let user = { name: "John" };
+
+let admin = user; // copy the reference
+```
+
+Now we have two variables, each one with the reference to the same object:
+
+
+
+We can use any variable to access the object and modify its contents:
+
+```js run
+let user = { name: 'John' };
+
+let admin = user;
+
+*!*
+admin.name = 'Pete'; // changed by the "admin" reference
+*/!*
+
+alert(*!*user.name*/!*); // 'Pete', changes are seen from the "user" reference
+```
+
+The example above demonstrates that there is only one object. As if we had a cabinet with two keys and used one of them (`admin`) to get into it. Then, if we later use another key (`user`) we can see changes.
+
+## Comparison by reference
+
+The equality `==` and strict equality `===` operators for objects work exactly the same.
+
+**Two objects are equal only if they are the same object.**
+
+Here two variables reference the same object, thus they are equal:
+
+```js run
+let a = {};
+let b = a; // copy the reference
+
+alert( a == b ); // true, both variables reference the same object
+alert( a === b ); // true
+```
+
+And here two independent objects are not equal, even though both are empty:
+
+```js run
+let a = {};
+let b = {}; // two independent objects
+
+alert( a == b ); // false
+```
+
+For comparisons like `obj1 > obj2` or for a comparison against a primitive `obj == 5`, objects are converted to primitives. We'll study how object conversions work very soon, but to tell the truth, such comparisons occur very rarely, usually as a result of a coding mistake.
+
+## Cloning and merging, Object.assign
+
+So, copying an object variable creates one more reference to the same object.
+
+But what if we need to duplicate an object? Create an independent copy, a clone?
+
+That's also doable, but a little bit more difficult, because there's no built-in method for that in JavaScript. Actually, that's rarely needed. Copying by reference is good most of the time.
+
+But if we really want that, then we need to create a new object and replicate the structure of the existing one by iterating over its properties and copying them on the primitive level.
+
+Like this:
+
+```js run
+let user = {
+ name: "John",
+ age: 30
+};
+
+*!*
+let clone = {}; // the new empty object
+
+// let's copy all user properties into it
+for (let key in user) {
+ clone[key] = user[key];
+}
+*/!*
+
+// now clone is a fully independent object with the same content
+clone.name = "Pete"; // changed the data in it
+
+alert( user.name ); // still John in the original object
+```
+
+Also we can use the method [Object.assign](mdn:js/Object/assign) for that.
+
+The syntax is:
+
+```js
+Object.assign(dest, [src1, src2, src3...])
+```
+
+- 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`.
+
+For instance, we can use it to merge several objects into one:
+```js
+let user = { name: "John" };
+
+let permissions1 = { canView: true };
+let permissions2 = { canEdit: true };
+
+*!*
+// copies all properties from permissions1 and permissions2 into user
+Object.assign(user, permissions1, permissions2);
+*/!*
+
+// now user = { name: "John", canView: true, canEdit: true }
+```
+
+If the copied property name already exists, it gets overwritten:
+
+```js run
+let user = { name: "John" };
+
+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:
+
+```js
+let user = {
+ name: "John",
+ age: 30
+};
+
+*!*
+let clone = Object.assign({}, user);
+*/!*
+```
+
+It copies all properties of `user` into the empty object and returns it.
+
+## Nested cloning
+
+Until now we assumed that all properties of `user` are primitive. But properties can be references to other objects. What to do with them?
+
+Like this:
+```js run
+let user = {
+ name: "John",
+ sizes: {
+ height: 182,
+ width: 50
+ }
+};
+
+alert( user.sizes.height ); // 182
+```
+
+Now it's not enough to copy `clone.sizes = user.sizes`, because the `user.sizes` is an object, it will be copied by reference. So `clone` and `user` will share the same sizes:
+
+Like this:
+
+```js run
+let user = {
+ name: "John",
+ sizes: {
+ height: 182,
+ width: 50
+ }
+};
+
+let clone = Object.assign({}, user);
+
+alert( user.sizes === clone.sizes ); // true, same object
+
+// user and clone share sizes
+user.sizes.width++; // change a property from one place
+alert(clone.sizes.width); // 51, see the result from the other one
+```
+
+To fix that, we should use the cloning loop that examines each value of `user[key]` and, if it's an object, then replicate its structure as well. That is called a "deep cloning".
+
+There's a standard algorithm for deep cloning that handles the case above and more complex cases, called the [Structured cloning algorithm](https://html.spec.whatwg.org/multipage/structured-data.html#safe-passing-of-structured-data).
+
+We can use recursion to implement it. Or, not to reinvent the wheel, take an existing implementation, for instance [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep) from the JavaScript library [lodash](https://lodash.com).
+
+## Summary
+
+Objects are assigned and copied by reference. In other words, a variable stores not the "object value", but a "reference" (address in memory) for the value. So copying such a variable or passing it as a function argument copies that reference, not the object.
+
+All operations via copied references (like adding/removing properties) are performed on the same single object.
+
+To make a "real copy" (a clone) we can use `Object.assign` for the so-called "shallow copy" (nested objects are copied by reference) or a "deep cloning" function, such as [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep).
diff --git a/1-js/04-object-basics/01-object/variable-contains-reference.svg b/1-js/04-object-basics/02-object-copy/variable-contains-reference.svg
similarity index 100%
rename from 1-js/04-object-basics/01-object/variable-contains-reference.svg
rename to 1-js/04-object-basics/02-object-copy/variable-contains-reference.svg
diff --git a/1-js/04-object-basics/01-object/variable-copy-reference.svg b/1-js/04-object-basics/02-object-copy/variable-copy-reference.svg
similarity index 100%
rename from 1-js/04-object-basics/01-object/variable-copy-reference.svg
rename to 1-js/04-object-basics/02-object-copy/variable-copy-reference.svg
diff --git a/1-js/04-object-basics/01-object/variable-copy-value.svg b/1-js/04-object-basics/02-object-copy/variable-copy-value.svg
similarity index 100%
rename from 1-js/04-object-basics/01-object/variable-copy-value.svg
rename to 1-js/04-object-basics/02-object-copy/variable-copy-value.svg
diff --git a/1-js/04-object-basics/02-garbage-collection/article.md b/1-js/04-object-basics/03-garbage-collection/article.md
similarity index 86%
rename from 1-js/04-object-basics/02-garbage-collection/article.md
rename to 1-js/04-object-basics/03-garbage-collection/article.md
index 3882dfe2ec..d0bc8aa173 100644
--- a/1-js/04-object-basics/02-garbage-collection/article.md
+++ b/1-js/04-object-basics/03-garbage-collection/article.md
@@ -23,7 +23,11 @@
2. Любое другое значение считается достижимым, если оно доступно из корня по ссылке или по цепочке ссылок.
+<<<<<<< HEAD:1-js/04-object-basics/02-garbage-collection/article.md
Например, если в локальной переменной есть объект, и он имеет свойство, в котором хранится ссылка на другой объект, то этот объект считается достижимым. И те, на которые он ссылается, тоже достижимы. Далее вы познакомитесь с подробными примерами на эту тему.
+=======
+ For instance, if there's an object in a global variable, and that object has a property referencing another object, that object is considered reachable. And those that it references are also reachable. Detailed examples to follow.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/04-object-basics/03-garbage-collection/article.md
В интерпретаторе JavaScript есть фоновый процесс, который называется [сборщик мусора](https://ru.wikipedia.org/wiki/Сборка_мусора). Он следит за всеми объектами и удаляет те, которые стали недостижимы.
@@ -153,11 +157,19 @@ family = null;
Согласно этому алгоритму, сборщик мусора регулярно выполняет следующие шаги:
+<<<<<<< HEAD:1-js/04-object-basics/02-garbage-collection/article.md
- Сборщик мусора "помечает" (запоминает) все корневые объекты.
- Затем он идёт по их ссылкам и помечает все найденные объекты.
- Затем он идёт по ссылкам помеченных объектов и помечает объекты, на которые есть ссылка от них. Все объекты запоминаются, чтобы в будущем не посещать один и тот же объект дважды.
- ...И так далее, пока не будут посещены все ссылки (достижимые от корней).
- Все непомеченные объекты удаляются.
+=======
+- The garbage collector takes roots and "marks" (remembers) them.
+- Then it visits and "marks" all references from them.
+- Then it visits marked objects and marks *their* references. All visited objects are remembered, so as not to visit the same object twice in the future.
+- ...And so on until every reachable (from the roots) references are visited.
+- All objects except marked ones are removed.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/04-object-basics/03-garbage-collection/article.md
Например, пусть наша структура объектов выглядит так:
@@ -181,9 +193,15 @@ family = null;

+<<<<<<< HEAD:1-js/04-object-basics/02-garbage-collection/article.md
Это и есть принцип работы сборки мусора.
Интерпретаторы JavaScript применяют множество оптимизаций, чтобы сборка мусора работала быстрее и не влияла на производительность.
+=======
+We can also imagine the process as spilling a huge bucket of paint from the roots, that flows through all references and marks all reachable objects. The unmarked ones are then removed.
+
+That's the concept of how garbage collection works. JavaScript engines apply many optimizations to make it run faster and not affect the execution.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/04-object-basics/03-garbage-collection/article.md
Вот некоторые из оптимизаций:
@@ -191,7 +209,11 @@ family = null;
- **Инкрементальная сборка (Incremental collection)** - если объектов много, то обход всех ссылок и пометка достижимых объектов может занять значительное время и привести к видимым задержкам выполнения скрипта. Поэтому интерпретатор пытается организовать сборку мусора поэтапно. Этапы выполняются по отдельности один за другим. Это требует дополнительного учёта для отслеживания изменений между этапами, но зато теперь у нас есть много крошечных задержек вместо одной большой.
- **Сборка в свободное время (Idle-time collection)** - чтобы уменьшить возможное влияние на производительность, сборщик мусора старается работать только во время простоя процессора.
+<<<<<<< HEAD:1-js/04-object-basics/02-garbage-collection/article.md
Существуют и другие способы оптимизации и разновидности алгоритмов сборки мусора. Но как бы мне ни хотелось описать их здесь, я должен воздержаться от этого, потому что разные интерпретаторы JavaScript применяют разные приёмы и хитрости. И, что более важно, всё меняется по мере развития интерпретаторов, поэтому углубляться в эту тему заранее, без реальной необходимости, вероятно, не стоит. Если, конечно, это не вопрос чистого интереса, тогда для вас будут полезны некоторые ссылки ниже.
+=======
+There exist other optimizations and flavours of garbage collection algorithms. As much as I'd like to describe them here, I have to hold off, because different engines implement different tweaks and techniques. And, what's even more important, things change as engines develop, so studying deeper "in advance", without a real need is probably not worth that. Unless, of course, it is a matter of pure interest, then there will be some links for you below.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/04-object-basics/03-garbage-collection/article.md
## Итого
diff --git a/1-js/04-object-basics/02-garbage-collection/family-delete-refs.svg b/1-js/04-object-basics/03-garbage-collection/family-delete-refs.svg
similarity index 100%
rename from 1-js/04-object-basics/02-garbage-collection/family-delete-refs.svg
rename to 1-js/04-object-basics/03-garbage-collection/family-delete-refs.svg
diff --git a/1-js/04-object-basics/02-garbage-collection/family-no-family.svg b/1-js/04-object-basics/03-garbage-collection/family-no-family.svg
similarity index 100%
rename from 1-js/04-object-basics/02-garbage-collection/family-no-family.svg
rename to 1-js/04-object-basics/03-garbage-collection/family-no-family.svg
diff --git a/1-js/04-object-basics/02-garbage-collection/family-no-father-2.svg b/1-js/04-object-basics/03-garbage-collection/family-no-father-2.svg
similarity index 100%
rename from 1-js/04-object-basics/02-garbage-collection/family-no-father-2.svg
rename to 1-js/04-object-basics/03-garbage-collection/family-no-father-2.svg
diff --git a/1-js/04-object-basics/02-garbage-collection/family-no-father.svg b/1-js/04-object-basics/03-garbage-collection/family-no-father.svg
similarity index 100%
rename from 1-js/04-object-basics/02-garbage-collection/family-no-father.svg
rename to 1-js/04-object-basics/03-garbage-collection/family-no-father.svg
diff --git a/1-js/04-object-basics/02-garbage-collection/family.svg b/1-js/04-object-basics/03-garbage-collection/family.svg
similarity index 100%
rename from 1-js/04-object-basics/02-garbage-collection/family.svg
rename to 1-js/04-object-basics/03-garbage-collection/family.svg
diff --git a/1-js/04-object-basics/02-garbage-collection/garbage-collection-1.svg b/1-js/04-object-basics/03-garbage-collection/garbage-collection-1.svg
similarity index 100%
rename from 1-js/04-object-basics/02-garbage-collection/garbage-collection-1.svg
rename to 1-js/04-object-basics/03-garbage-collection/garbage-collection-1.svg
diff --git a/1-js/04-object-basics/02-garbage-collection/garbage-collection-2.svg b/1-js/04-object-basics/03-garbage-collection/garbage-collection-2.svg
similarity index 100%
rename from 1-js/04-object-basics/02-garbage-collection/garbage-collection-2.svg
rename to 1-js/04-object-basics/03-garbage-collection/garbage-collection-2.svg
diff --git a/1-js/04-object-basics/02-garbage-collection/garbage-collection-3.svg b/1-js/04-object-basics/03-garbage-collection/garbage-collection-3.svg
similarity index 100%
rename from 1-js/04-object-basics/02-garbage-collection/garbage-collection-3.svg
rename to 1-js/04-object-basics/03-garbage-collection/garbage-collection-3.svg
diff --git a/1-js/04-object-basics/02-garbage-collection/garbage-collection-4.svg b/1-js/04-object-basics/03-garbage-collection/garbage-collection-4.svg
similarity index 100%
rename from 1-js/04-object-basics/02-garbage-collection/garbage-collection-4.svg
rename to 1-js/04-object-basics/03-garbage-collection/garbage-collection-4.svg
diff --git a/1-js/04-object-basics/03-garbage-collection/garbage-collection-5.svg b/1-js/04-object-basics/03-garbage-collection/garbage-collection-5.svg
new file mode 100644
index 0000000000..abb127ab23
--- /dev/null
+++ b/1-js/04-object-basics/03-garbage-collection/garbage-collection-5.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/04-object-basics/02-garbage-collection/memory-user-john-admin.svg b/1-js/04-object-basics/03-garbage-collection/memory-user-john-admin.svg
similarity index 100%
rename from 1-js/04-object-basics/02-garbage-collection/memory-user-john-admin.svg
rename to 1-js/04-object-basics/03-garbage-collection/memory-user-john-admin.svg
diff --git a/1-js/04-object-basics/02-garbage-collection/memory-user-john-lost.svg b/1-js/04-object-basics/03-garbage-collection/memory-user-john-lost.svg
similarity index 100%
rename from 1-js/04-object-basics/02-garbage-collection/memory-user-john-lost.svg
rename to 1-js/04-object-basics/03-garbage-collection/memory-user-john-lost.svg
diff --git a/1-js/04-object-basics/02-garbage-collection/memory-user-john.svg b/1-js/04-object-basics/03-garbage-collection/memory-user-john.svg
similarity index 100%
rename from 1-js/04-object-basics/02-garbage-collection/memory-user-john.svg
rename to 1-js/04-object-basics/03-garbage-collection/memory-user-john.svg
diff --git a/1-js/04-object-basics/04-object-methods/4-object-property-this/solution.md b/1-js/04-object-basics/04-object-methods/4-object-property-this/solution.md
index fcdae3f3e5..da3f240c35 100644
--- a/1-js/04-object-basics/04-object-methods/4-object-property-this/solution.md
+++ b/1-js/04-object-basics/04-object-methods/4-object-property-this/solution.md
@@ -22,7 +22,22 @@ alert( user.ref.name ); // Error: Cannot read property 'name' of undefined
Таким образом, при создании объекта `ref: this` берёт текущее значение `this` функции `makeUser()`.
+<<<<<<< HEAD
А вот противоположный случай:
+=======
+We can rewrite the function and return the same `this` with `undefined` value:
+
+```js run
+function makeUser(){
+ return this; // this time there's no object literal
+}
+
+alert( makeUser().name ); // Error: Cannot read property 'name' of undefined
+```
+As you can see the result of `alert( makeUser().name )` is the same as the result of `alert( user.ref.name )` from the previous example.
+
+Here's the opposite case:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js run
function makeUser() {
diff --git a/1-js/04-object-basics/04-object-methods/article.md b/1-js/04-object-basics/04-object-methods/article.md
index b4a3c06e88..4fd4f7532a 100644
--- a/1-js/04-object-basics/04-object-methods/article.md
+++ b/1-js/04-object-basics/04-object-methods/article.md
@@ -64,7 +64,11 @@ user.sayHi(); // Привет!
```smart header="Объектно-ориентированное программирование"
Когда мы пишем наш код, используя объекты для представления сущностей реального мира, - это называется [объектно-ориентированное программирование](https://ru.wikipedia.org/wiki/%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%BD%D0%BE-%D0%BE%D1%80%D0%B8%D0%B5%D0%BD%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D0%BE%D0%B5_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5) или сокращённо: "ООП".
+<<<<<<< HEAD
ООП является большой предметной областью и интересной наукой само по себе. Как выбрать правильные сущности? Как организовать взаимодействие между ними? Это -- создание архитектуры, и есть хорошие книги по этой теме, такие как "Приёмы объектно-ориентированного проектирования. Паттерны проектирования" авторов Эрих Гамма, Ричард Хелм, Ральф Джонсон, Джон Влиссидес или "Объектно-ориентированный анализ и проектирование с примерами приложений" Гради Буча, а также ещё множество других книг.
+=======
+OOP is a big thing, an interesting science of its own. How to choose the right entities? How to organize the interaction between them? That's architecture, and there are great books on that topic, like "Design Patterns: Elements of Reusable Object-Oriented Software" by E. Gamma, R. Helm, R. Johnson, J. Vissides or "Object-Oriented Analysis and Design with Applications" by G. Booch, and more.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```
### Сокращённая запись метода
@@ -234,6 +238,7 @@ sayHi(); // undefined
Здесь мы не будем судить о том, является ли это решение в языке хорошим или плохим. Мы должны понимать, как с этим работать, чтобы получать выгоды и избегать проблем.
```
+<<<<<<< HEAD
## Внутренняя реализация: Ссылочный тип
```warn header="Продвинутая возможность языка"
@@ -328,6 +333,9 @@ hi(); // Ошибка, потому что значением this являет
Таким образом, значение `this` передаётся правильно, только если функция вызывается напрямую с использованием синтаксиса точки `obj.method()` или квадратных скобок `obj['method']()` (они делают то же самое). Позднее в этом учебнике мы изучим различные варианты решения проблемы потери значения `this`. Например, такие как [func.bind()](/bind#solution-2-bind).
## У стрелочных функций нет "this"
+=======
+## Arrow functions have no "this"
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Стрелочные функции особенные: у них нет своего "собственного" `this`. Если мы используем `this` внутри стрелочной функции, то его значение берётся из внешней "нормальной" функции.
diff --git a/1-js/04-object-basics/07-optional-chaining/article.md b/1-js/04-object-basics/07-optional-chaining/article.md
new file mode 100644
index 0000000000..974689020b
--- /dev/null
+++ b/1-js/04-object-basics/07-optional-chaining/article.md
@@ -0,0 +1,175 @@
+
+# Optional chaining '?.'
+
+[recent browser="new"]
+
+The optional chaining `?.` is an error-proof way to access nested object properties, even if an intermediate property doesn't exist.
+
+## The problem
+
+If you've just started to read the tutorial and learn JavaScript, maybe the problem hasn't touched you yet, but it's quite common.
+
+For example, some of our users have addresses, but few did not provide them. Then we can't safely read `user.address.street`:
+
+```js run
+let user = {}; // the user happens to be without address
+
+alert(user.address.street); // Error!
+```
+
+Or, in the web development, we'd like to get an information about an element on the page, but it may not exist:
+
+```js run
+// Error if the result of querySelector(...) is null
+let html = document.querySelector('.my-element').innerHTML;
+```
+
+Before `?.` appeared in the language, the `&&` operator was used to work around that.
+
+For example:
+
+```js run
+let user = {}; // user has no address
+
+alert( user && user.address && user.address.street ); // undefined (no error)
+```
+
+AND'ing the whole path to the property ensures that all components exist, but is cumbersome to write.
+
+## Optional chaining
+
+The optional chaining `?.` stops the evaluation and returns `undefined` if the part before `?.` is `undefined` or `null`.
+
+**Further in this article, for brevity, we'll be saying that something "exists" if it's not `null` and not `undefined`.**
+
+Here's the safe way to access `user.address.street`:
+
+```js run
+let user = {}; // user has no address
+
+alert( user?.address?.street ); // undefined (no error)
+```
+
+Reading the address with `user?.address` works even if `user` object doesn't exist:
+
+```js run
+let user = null;
+
+alert( user?.address ); // undefined
+alert( user?.address.street ); // undefined
+```
+
+Please note: the `?.` syntax makes optional the value before it, but not any further.
+
+In the example above, `user?.` allows only `user` to be `null/undefined`.
+
+On the other hand, if `user` does exist, then it must have `user.address` property, otherwise `user?.address.street` gives an error at the second dot.
+
+```warn header="Don't overuse the optional chaining"
+We should use `?.` only where it's ok that something doesn't exist.
+
+For example, if according to our coding logic `user` object must be there, but `address` is optional, then `user.address?.street` would be better.
+
+So, if `user` happens to be undefined due to a mistake, we'll know about it and fix it. Otherwise, coding errors can be silenced where not appropriate, and become more difficult to debug.
+```
+
+````warn header="The variable before `?.` must be declared"
+If there's no variable `user` at all, then `user?.anything` triggers an error:
+
+```js run
+// ReferenceError: user is not defined
+user?.address;
+```
+There must be `let/const/var user`. The optional chaining works only for declared variables.
+````
+
+## Short-circuiting
+
+As it was said before, the `?.` immediately stops ("short-circuits") the evaluation if the left part doesn't exist.
+
+So, if there are any further function calls or side effects, they don't occur:
+
+```js run
+let user = null;
+let x = 0;
+
+user?.sayHi(x++); // nothing happens
+
+alert(x); // 0, value not incremented
+```
+
+## Other cases: ?.(), ?.[]
+
+The optional chaining `?.` is not an operator, but a special syntax construct, that also works with functions and square brackets.
+
+For example, `?.()` is used to call a function that may not exist.
+
+In the code below, some of our users have `admin` method, and some don't:
+
+```js run
+let user1 = {
+ admin() {
+ alert("I am admin");
+ }
+}
+
+let user2 = {};
+
+*!*
+user1.admin?.(); // I am admin
+user2.admin?.();
+*/!*
+```
+
+Here, in both lines we first use the dot `.` to get `admin` property, because the user object must exist, so it's safe read from it.
+
+Then `?.()` checks the left part: if the admin function exists, then it runs (for `user1`). Otherwise (for `user2`) the evaluation stops without errors.
+
+The `?.[]` syntax also works, if we'd like to use brackets `[]` to access properties instead of dot `.`. Similar to previous cases, it allows to safely read a property from an object that may not exist.
+
+```js run
+let user1 = {
+ firstName: "John"
+};
+
+let user2 = null; // Imagine, we couldn't authorize the user
+
+let key = "firstName";
+
+alert( user1?.[key] ); // John
+alert( user2?.[key] ); // undefined
+
+alert( user1?.[key]?.something?.not?.existing); // undefined
+```
+
+Also we can use `?.` with `delete`:
+
+```js run
+delete user?.name; // delete user.name if user exists
+```
+
+```warn header="We can use `?.` for safe reading and deleting, but not writing"
+The optional chaining `?.` has no use at the left side of an assignment:
+
+```js run
+// the idea of the code below is to write user.name, if user exists
+
+user?.name = "John"; // Error, doesn't work
+// because it evaluates to undefined = "John"
+```
+
+## Summary
+
+The `?.` syntax has three forms:
+
+1. `obj?.prop` -- returns `obj.prop` if `obj` exists, otherwise `undefined`.
+2. `obj?.[prop]` -- returns `obj[prop]` if `obj` exists, otherwise `undefined`.
+3. `obj?.method()` -- calls `obj.method()` if `obj` exists, otherwise returns `undefined`.
+
+As we can see, all of them are straightforward and simple to use. The `?.` checks the left part for `null/undefined` and allows the evaluation to proceed if it's not so.
+
+A chain of `?.` allows to safely access nested properties.
+
+Still, we should apply `?.` carefully, only where it's ok that the left part doesn't to exist.
+
+So that it won't hide programming errors from us, if they occur.
diff --git a/1-js/04-object-basics/03-symbol/article.md b/1-js/04-object-basics/08-symbol/article.md
similarity index 93%
rename from 1-js/04-object-basics/03-symbol/article.md
rename to 1-js/04-object-basics/08-symbol/article.md
index 30135ecf97..229a87544c 100644
--- a/1-js/04-object-basics/03-symbol/article.md
+++ b/1-js/04-object-basics/08-symbol/article.md
@@ -18,8 +18,13 @@ let id = Symbol();
При создании символу можно дать описание (также называемое имя), в основном использующееся для отладки кода:
+<<<<<<< HEAD:1-js/04-object-basics/03-symbol/article.md
```js run
// Создаём символ id с описанием (именем) "id"
+=======
+```js
+// id is a symbol with the description "id"
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/04-object-basics/08-symbol/article.md
let id = Symbol("id");
```
@@ -121,7 +126,11 @@ user.id = "Их идентификатор"
// Ой! Свойство перезаписано сторонней библиотекой!
```
+<<<<<<< HEAD:1-js/04-object-basics/03-symbol/article.md
### Символы в литеральном объекте
+=======
+### Symbols in an object literal
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/04-object-basics/08-symbol/article.md
Если мы хотим использовать символ при литеральном объявлении объекта `{...}`, его необходимо заключить в квадратные скобки.
@@ -133,7 +142,11 @@ let id = Symbol("id");
let user = {
name: "Вася",
*!*
+<<<<<<< HEAD:1-js/04-object-basics/03-symbol/article.md
[id]: 123 // просто "id: 123" не сработает
+=======
+ [id]: 123 // not "id": 123
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/04-object-basics/08-symbol/article.md
*/!*
};
```
@@ -176,10 +189,16 @@ let clone = Object.assign({}, user);
alert( clone[id] ); // 123
```
+<<<<<<< HEAD:1-js/04-object-basics/03-symbol/article.md
Здесь нет никакого парадокса или противоречия. Так и задумано. Идея заключается в том, что, когда мы клонируем или объединяем объекты, мы обычно хотим скопировать *все* свойства (включая такие свойства с ключами-символами, как, например, `id` в примере выше).
## Глобальные символы
+=======
+There's no paradox here. That's by design. The idea is that when we clone an object or merge objects, we usually want *all* properties to be copied (including symbols like `id`).
+
+## Global symbols
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/04-object-basics/08-symbol/article.md
Итак, как мы видели, обычно все символы уникальны, даже если их имена совпадают. Но иногда мы наоборот хотим, чтобы символы с одинаковыми именами были одной сущностью. Например, разные части нашего приложения хотят получить доступ к символу `"id"`, подразумевая именно одно и то же свойство.
@@ -226,7 +245,11 @@ alert( Symbol.keyFor(sym) ); // name
alert( Symbol.keyFor(sym2) ); // id
```
+<<<<<<< HEAD:1-js/04-object-basics/03-symbol/article.md
Внутри метода `Symbol.keyFor` используется глобальный реестр символов для нахождения имени символа. Так что этот метод не будет работать для неглобальных символов. Если символ неглобальный, метод не сможет его найти и вернёт `undefined`.
+=======
+The `Symbol.keyFor` internally uses the global symbol registry to look up the key for the symbol. So it doesn't work for non-global symbols. If the symbol is not global, it won't be able to find it and returns `undefined`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/04-object-basics/08-symbol/article.md
Впрочем, для любых символов доступно свойство `description`.
diff --git a/1-js/04-object-basics/05-object-toprimitive/article.md b/1-js/04-object-basics/09-object-toprimitive/article.md
similarity index 75%
rename from 1-js/04-object-basics/05-object-toprimitive/article.md
rename to 1-js/04-object-basics/09-object-toprimitive/article.md
index 4ba85fb740..b5de697af0 100644
--- a/1-js/04-object-basics/05-object-toprimitive/article.md
+++ b/1-js/04-object-basics/09-object-toprimitive/article.md
@@ -46,21 +46,43 @@
`"default"`
: Происходит редко, когда оператор "не уверен", какой тип ожидать.
+<<<<<<< HEAD:1-js/04-object-basics/05-object-toprimitive/article.md
Например, бинарный плюс `+` может работать с обоими типами: строками (объединять их) и числами (складывать). Таким образом, и те, и другие будут вычисляться. Или когда происходит сравнение объектов с помощью нестрогого равенства `==` со строкой, числом или символом, и неясно, какое преобразование должно быть выполнено.
```js
// бинарный плюс
let total = car1 + car2;
+=======
+ For instance, binary plus `+` can work both with strings (concatenates them) and numbers (adds them), so both strings and numbers would do. So if a binary plus gets an object as an argument, it uses the `"default"` hint to convert it.
- // obj == string/number/symbol
+ Also, if an object is compared using `==` with a string, number or a symbol, it's also unclear which conversion should be done, so the `"default"` hint is used.
+
+ ```js
+ // binary plus uses the "default" hint
+ let total = obj1 + obj2;
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/04-object-basics/09-object-toprimitive/article.md
+
+ // obj == number uses the "default" hint
if (user == 1) { ... };
```
+<<<<<<< HEAD:1-js/04-object-basics/05-object-toprimitive/article.md
Оператор больше/меньше `<>` также может работать как со строками, так и с числами. Однако, по историческим причинам он использует хинт "number", а не "default".
На практике все встроенные объекты, исключая `Date` (мы познакомимся с ним чуть позже), реализуют `"default"` преобразования тем же способом, что и `"number"`. И нам следует поступать также.
Обратите внимание, что существуют лишь три варианта хинтов. Всё настолько просто. Не существует хинта со значением "boolean" (все объекты являются `true` в логическом контексте) или каких-либо ещё. И если мы считаем `"default"` и `"number"` одинаковыми, как большинство встроенных объектов, то остаются всего два варианта преобразований.
+=======
+ The greater and less comparison operators, such as `<` `>`, can work with both strings and numbers too. Still, they use the `"number"` hint, not `"default"`. That's for historical reasons.
+
+ In practice though, we don't need to remember these peculiar details, because all built-in objects except for one case (`Date` object, we'll learn it later) implement `"default"` conversion the same way as `"number"`. And we can do the same.
+
+```smart header="No `\"boolean\"` hint"
+Please note -- there are only three hints. It's that simple.
+
+There is no "boolean" hint (all objects are `true` in boolean context) or anything else. And if we treat `"default"` and `"number"` the same, like most built-ins do, then there are only two conversions.
+```
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/04-object-basics/09-object-toprimitive/article.md
**В процессе преобразования движок JavaScript пытается найти и вызвать три следующих метода объекта:**
@@ -112,7 +134,33 @@ alert(user + 500); // hint: default -> 1500
- `toString -> valueOf` для хинта со значением "string".
- `valueOf -> toString` -- в ином случае.
+<<<<<<< HEAD:1-js/04-object-basics/05-object-toprimitive/article.md
Для примера, используем их в реализации всё того же объекта `user`. Воспроизведём его поведение комбинацией методов `toString` и `valueOf`:
+=======
+These methods must return a primitive value. If `toString` or `valueOf` returns an object, then it's ignored (same as if there were no method).
+
+By default, a plain object has following `toString` and `valueOf` methods:
+
+- The `toString` method returns a string `"[object Object]"`.
+- The `valueOf` method returns the object itself.
+
+Here's the demo:
+
+```js run
+let user = {name: "John"};
+
+alert(user); // [object Object]
+alert(user.valueOf() === user); // true
+```
+
+So if we try to use an object as a string, like in an `alert` or so, then by default we see `[object Object]`.
+
+And the default `valueOf` is mentioned here only for the sake of completeness, to avoid any confusion. As you can see, it returns the object itself, and so is ignored. Don't ask me why, that's for historical reasons. So we can assume it doesn't exist.
+
+Let's implement these methods.
+
+For instance, here `user` does the same as above using a combination of `toString` and `valueOf` instead of `Symbol.toPrimitive`:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/04-object-basics/09-object-toprimitive/article.md
```js run
let user = {
@@ -158,7 +206,11 @@ alert(user + 500); // toString -> John500
## Возвращаемые типы
+<<<<<<< HEAD:1-js/04-object-basics/05-object-toprimitive/article.md
Важно понимать, что все описанные методы для преобразований объектов не обязаны возвращать именно требуемый "хинтом" тип примитива.
+=======
+There is no control whether `toString` returns exactly a string, or whether `Symbol.toPrimitive` method returns a number for a hint `"number"`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/04-object-basics/09-object-toprimitive/article.md
Нет обязательного требования, чтобы `toString()` возвращал именно строку, или чтобы метод `Symbol.toPrimitive` возвращал именно число для хинта "number".
@@ -170,12 +222,23 @@ alert(user + 500); // toString -> John500
Метод `Symbol.toPrimitive`, напротив, *обязан* возвращать примитив, иначе будет ошибка.
```
+<<<<<<< HEAD:1-js/04-object-basics/05-object-toprimitive/article.md
## Последующие операции
Операция, инициировавшая преобразование, получает примитив и затем продолжает работу с ним, производя дальнейшие преобразования, если это необходимо.
+=======
+## Further conversions
+
+As we know already, many operators and functions perform type conversions, e.g. multiplication `*` converts operands to numbers.
+
+If we pass an object as an argument, then there are two stages:
+1. The object is converted to a primitive (using the rules described above).
+2. If the resulting primitive isn't of the right type, it's converted.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/04-object-basics/09-object-toprimitive/article.md
Например:
+<<<<<<< HEAD:1-js/04-object-basics/05-object-toprimitive/article.md
- Математические операции, исключая бинарный плюс, преобразуют примитив к числу:
```js run
@@ -200,6 +263,33 @@ alert(user + 500); // toString -> John500
alert(obj + 2); // 22 (преобразование к примитиву вернуло строку => конкатенация)
```
+=======
+```js run
+let obj = {
+ // toString handles all conversions in the absence of other methods
+ toString() {
+ return "2";
+ }
+};
+
+alert(obj * 2); // 4, object converted to primitive "2", then multiplication made it a number
+```
+
+1. The multiplication `obj * 2` first converts the object to primitive (that's a string `"2"`).
+2. Then `"2" * 2` becomes `2 * 2` (the string is converted to number).
+
+Binary plus will concatenate strings in the same situation, as it gladly accepts a string:
+
+```js run
+let obj = {
+ toString() {
+ return "2";
+ }
+};
+
+alert(obj + 2); // 22 ("2" + 2), conversion to primitive returned a string => concatenation
+```
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/04-object-basics/09-object-toprimitive/article.md
## Итого
diff --git a/1-js/05-data-types/01-primitives-methods/article.md b/1-js/05-data-types/01-primitives-methods/article.md
index 78c3f734a3..382e967398 100644
--- a/1-js/05-data-types/01-primitives-methods/article.md
+++ b/1-js/05-data-types/01-primitives-methods/article.md
@@ -6,8 +6,13 @@ JavaScript позволяет нам работать с примитивным
Примитив
+<<<<<<< HEAD
- Это - значение «примитивного» типа.
- Есть 7 примитивных типов: `string`, `number`, `boolean`, `symbol`, `null`, `undefined` и `bigint`.
+=======
+- Is a value of a primitive type.
+- There are 7 primitive types: `string`, `number`, `bigint`, `boolean`, `symbol`, `null` and `undefined`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Объект
diff --git a/1-js/05-data-types/02-number/article.md b/1-js/05-data-types/02-number/article.md
index 50ebfc494c..8ffebbb61e 100644
--- a/1-js/05-data-types/02-number/article.md
+++ b/1-js/05-data-types/02-number/article.md
@@ -1,10 +1,20 @@
# Числа
+<<<<<<< HEAD
В современном JavaScript существует два типа чисел:
1. Обычные числа в JavaScript хранятся в 64-битном формате [IEEE-754](http://en.wikipedia.org/wiki/IEEE_754-1985), который также называют "числа с плавающей точкой двойной точности" (double precision floating point numbers). Это числа, которые мы будем использовать чаще всего. Мы поговорим о них в этой главе.
2. `BigInt` числа дают возможность работать с целыми числами произвольной длины. Они нужны достаточно редко и используются в случаях, когда необходимо работать со значениями более чем 253 или менее чем -253. Так как `BigInt` числа нужны достаточно редко, мы рассмотрим их в отдельной главе .
В данной главе мы рассмотрим только первый тип чисел: числа типа `number`. Давайте глубже изучим, как с ними работать в JavaScript.
+=======
+In modern JavaScript, there are two types of numbers:
+
+1. Regular numbers in JavaScript are stored in 64-bit format [IEEE-754](https://en.wikipedia.org/wiki/IEEE_754-2008_revision), also known as "double precision floating point numbers". These are numbers that we're using most of the time, and we'll talk about them in this chapter.
+
+2. BigInt numbers, to represent integers of arbitrary length. They are sometimes needed, because a regular number can't exceed 253 or be less than -253. As bigints are used in few special areas, we devote them a special chapter .
+
+So here we'll talk about regular numbers. Let's expand our knowledge of them.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
## Способы записи числа
@@ -31,14 +41,22 @@ alert( 7.3e9 ); // 7.3 миллиардов (7,300,000,000)
1.23e6 = 1.23 * 1000000
```
+<<<<<<< HEAD
Сейчас давайте запишем что-нибудь очень маленькое. К примеру, 1 микросекунду (одна миллионная секунды):
+=======
+Now let's write something very small. Say, 1 microsecond (one millionth of a second):
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js
let ms = 0.000001;
```
+<<<<<<< HEAD
Записать микросекунду в укороченном виде нам поможет `"e"`.
+=======
+Just like before, using `"e"` can help. If we'd like to avoid writing the zeroes explicitly, we could say the same as:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js
let ms = 1e-6; // шесть нулей, слева от 1
@@ -147,7 +165,11 @@ alert( num.toString(2) ); // 11111111
1. Умножить и разделить.
+<<<<<<< HEAD
Например, чтобы округлить число до второго знака после запятой, мы можем умножить число на `100`, вызвать функцию округления и разделить обратно.
+=======
+ For example, to round the number to the 2nd digit after the decimal, we can multiply the number by `100` (or a bigger power of 10), call the rounding function and then divide it back.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js run
let num = 1.23456;
@@ -203,7 +225,11 @@ alert( 0.1 + 0.2 == 0.3 ); // *!*false*/!*
alert( 0.1 + 0.2 ); // 0.30000000000000004
```
+<<<<<<< HEAD
Ой! Здесь гораздо больше последствий, чем просто некорректное сравнение. Представьте, вы делаете интернет-магазин и посетители формируют заказ из 2-х позиций за `$0.10` и `$0.20`. Итоговый заказ будет `$0.30000000000000004`. Это будет сюрпризом для всех.
+=======
+Ouch! There are more consequences than an incorrect comparison here. Imagine you're making an e-shopping site and the visitor puts `$0.10` and `$0.20` goods into their cart. The order total will be `$0.30000000000000004`. That would surprise anyone.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Но почему это происходит?
@@ -271,14 +297,22 @@ alert( 9999999999999999 ); // покажет 10000000000000000
```smart header="Два нуля"
Другим забавным следствием внутреннего представления чисел является наличие двух нулей: `0` и `-0`.
+<<<<<<< HEAD
Все потому, что знак представлен отдельным битом, так что, любое число может быть положительным и отрицательным, включая нуль.
+=======
+That's because a sign is represented by a single bit, so it can be set or not set for any number including a zero.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
В большинстве случаев это поведение незаметно, так как операторы в JavaScript воспринимают их одинаковыми.
```
+<<<<<<< HEAD
## Проверка: isFinite и isNaN
+=======
+## Tests: isFinite and isNaN
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Помните эти специальные числовые значения?
@@ -323,7 +357,11 @@ alert( isFinite(num) );
```smart header="Сравнение `Object.is`"
+<<<<<<< HEAD
Существует специальный метод [Object.is](mdn:js/Object/is), который сравнивает значения примерно как `===`, но более надёжен в двух особых ситуациях:
+=======
+There is a special built-in method [`Object.is`](mdn:js/Object/is) that compares values like `===`, but is more reliable for two edge cases:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
1. Работает с `NaN`: `Object.is(NaN, NaN) === true`, здесь он хорош.
2. Значения `0` и `-0` разные: `Object.is(0, -0) === false`, это редко используется, но технически эти значения разные.
@@ -409,16 +447,29 @@ alert( parseInt('2n9c', 36) ); // 123456
## Итого
+<<<<<<< HEAD
Чтобы писать числа с большим количеством нулей:
- Используйте краткую форму записи чисел - `"e"`, с указанным количеством нулей. Например: `123e6` это `123` с 6-ю нулями `123000000`.
- Отрицательное число после `"e"` приводит к делению числа на 1 с указанным количеством нулей. Например: `123e-6` это `0.000123` (`123` миллионных).
+=======
+To write numbers with many zeroes:
+
+- Append `"e"` with the zeroes count to the number. Like: `123e6` is the same as `123` with 6 zeroes `123000000`.
+- A negative number after `"e"` causes the number to be divided by 1 with given zeroes. E.g. `123e-6` means `0.000123` (`123` millionths).
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Для других систем счисления:
+<<<<<<< HEAD
- Можно записывать числа сразу в шестнадцатеричной (`0x`), восьмеричной (`0o`) и бинарной (`0b`) системах счисления
- `parseInt(str, base)` преобразует строку в целое число в соответствии с указанной системой счисления: `2 ≤ base ≤ 36`.
- `num.toString(base)` представляет число в строковом виде в указанной системе счисления `base`.
+=======
+- Can write numbers directly in hex (`0x`), octal (`0o`) and binary (`0b`) systems.
+- `parseInt(str, base)` parses the string `str` into an integer in numeral system with given `base`, `2 ≤ base ≤ 36`.
+- `num.toString(base)` converts a number to a string in the numeral system with the given `base`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Для преобразования значений типа `12pt` и `100px` в число:
diff --git a/1-js/05-data-types/03-string/article.md b/1-js/05-data-types/03-string/article.md
index 32133f9fc6..35abe78da4 100644
--- a/1-js/05-data-types/03-string/article.md
+++ b/1-js/05-data-types/03-string/article.md
@@ -397,7 +397,11 @@ alert( "Widget".endsWith("get") ); // true, "get" — окончание "Widget
```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
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```
Также для `start/end` можно задавать отрицательные значения. Это означает, что позиция определена как заданное количество символов *с конца строки*:
@@ -405,8 +409,13 @@ alert( "Widget".endsWith("get") ); // true, "get" — окончание "Widget
```js run
let str = "strin*!*gif*/!*y";
+<<<<<<< HEAD
// начинаем с позиции 4 справа, а заканчиваем на позиции 1 справа
alert( str.slice(-4, -1) ); // gif
+=======
+ // start at the 4th position from the right, end at the 1st from the right
+ alert( str.slice(-4, -1) ); // 'gif'
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```
`str.substring(start [, end])`
@@ -438,16 +447,24 @@ alert( "Widget".endsWith("get") ); // true, "get" — окончание "Widget
```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
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```
Значение первого аргумента может быть отрицательным, тогда позиция определяется с конца:
```js run
let str = "strin*!*gi*/!*fy";
+<<<<<<< HEAD
// gi, получаем 2 символа, начиная с позиции 4 с конца строки
alert( str.substr(-4, 2) );
+=======
+ alert( str.substr(-4, 2) ); // 'gi', from the 4th position get 2 characters
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```
Давайте подытожим, как работают эти методы, чтобы не запутаться:
@@ -540,7 +557,11 @@ alert( str );
Поэтому браузеру нужно знать, какой язык использовать для сравнения.
+<<<<<<< HEAD
К счастью, все современные браузеры (для IE10− нужна дополнительная библиотека [Intl.JS](https://github.com/andyearnshaw/Intl.js/)) поддерживают стандарт [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](http://www.ecma-international.org/ecma-402/1.0/ECMA-402.pdf).
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Для этого есть соответствующий метод.
diff --git a/1-js/05-data-types/04-array/10-maximal-subarray/task.md b/1-js/05-data-types/04-array/10-maximal-subarray/task.md
index 443d99789b..fcaffec61a 100644
--- a/1-js/05-data-types/04-array/10-maximal-subarray/task.md
+++ b/1-js/05-data-types/04-array/10-maximal-subarray/task.md
@@ -10,6 +10,7 @@ importance: 2
Функция `getMaxSubSum(arr)` должна возвращать эту сумму.
+<<<<<<< HEAD
Например:
```js
@@ -19,6 +20,17 @@ getMaxSubSum([-1, 2, 3, -9, *!*11*/!*]) = 11
getMaxSubSum([-2, -1, *!*1, 2*/!*]) = 3
getMaxSubSum([*!*100*/!*, -9, 2, -3, 5]) = 100
getMaxSubSum([*!*1, 2, 3*/!*]) = 6 (берём все)
+=======
+For instance:
+
+```js
+getMaxSubSum([-1, *!*2, 3*/!*, -9]) == 5 (the sum of highlighted items)
+getMaxSubSum([*!*2, -1, 2, 3*/!*, -9]) == 6
+getMaxSubSum([-1, 2, 3, -9, *!*11*/!*]) == 11
+getMaxSubSum([-2, -1, *!*1, 2*/!*]) == 3
+getMaxSubSum([*!*100*/!*, -9, 2, -3, 5]) == 100
+getMaxSubSum([*!*1, 2, 3*/!*]) == 6 (take all)
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```
Если все элементы отрицательные - ничего не берём(подмассив пустой) и сумма равна "0":
diff --git a/1-js/05-data-types/04-array/3-call-array-this/solution.md b/1-js/05-data-types/04-array/3-call-array-this/solution.md
index 097ba62a04..bc8bab16b9 100644
--- a/1-js/05-data-types/04-array/3-call-array-this/solution.md
+++ b/1-js/05-data-types/04-array/3-call-array-this/solution.md
@@ -9,7 +9,7 @@ arr.push(function() {
alert( this );
})
-arr[2](); // "a","b",function
+arr[2](); // a,b,function(){...}
```
У массива в итоге 3 элемента: сначала их было 2, плюс функция.
diff --git a/1-js/05-data-types/04-array/article.md b/1-js/05-data-types/04-array/article.md
index 6306a6a1ce..3fb32a20d9 100644
--- a/1-js/05-data-types/04-array/article.md
+++ b/1-js/05-data-types/04-array/article.md
@@ -121,7 +121,13 @@ let fruits = [
В компьютерных науках структура данных, делающая это возможным, называется [двусторонняя очередь](https://ru.wikipedia.org/wiki/Двухсторонняя_очередь).
+<<<<<<< HEAD
**Методы, работающие с концом массива:**
+=======
+In computer science the data structure that allows this, is called [deque](https://en.wikipedia.org/wiki/Double-ended_queue).
+
+**Methods that work with the end of the array:**
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
`pop`
: Удаляет последний элемент из массива и возвращает его:
@@ -152,8 +158,13 @@ let fruits = [
`shift`
: Удаляет из массива первый элемент и возвращает его:
+<<<<<<< HEAD
```js
let fruits = ["Яблоко", "Апельсин", "Груша"];
+=======
+ ```js run
+ let fruits = ["Apple", "Orange", "Pear"];
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
alert( fruits.shift() ); // удаляем Яблоко и выводим его
@@ -163,8 +174,13 @@ let fruits = [
`unshift`
: Добавляет элемент в начало массива:
+<<<<<<< HEAD
```js
let fruits = ["Апельсин", "Груша"];
+=======
+ ```js run
+ let fruits = ["Orange", "Pear"];
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
fruits.unshift('Яблоко');
@@ -189,7 +205,11 @@ alert( fruits );
Массивы расширяют объекты, так как предусматривают специальные методы для работы с упорядоченными коллекциями данных, а также свойство `length`. Но в основе всё равно лежит объект.
+<<<<<<< HEAD
Следует помнить, что в JavaScript существует 8 основных типов данных. Массив является объектом и, следовательно, ведёт себя как объект.
+=======
+Remember, there are only eight basic data types in JavaScript (see the [Data types](https://javascript.info/types) chapter for more info). Array is an object and thus behaves like an object.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Например, копируется по ссылке:
diff --git a/1-js/05-data-types/05-array-methods/12-reduce-object/_js.view/solution.js b/1-js/05-data-types/05-array-methods/12-reduce-object/_js.view/solution.js
new file mode 100644
index 0000000000..8dea23a06a
--- /dev/null
+++ b/1-js/05-data-types/05-array-methods/12-reduce-object/_js.view/solution.js
@@ -0,0 +1,6 @@
+function groupById(array) {
+ return array.reduce((obj, value) => {
+ obj[value.id] = value;
+ return obj;
+ }, {})
+}
diff --git a/1-js/05-data-types/05-array-methods/12-reduce-object/_js.view/test.js b/1-js/05-data-types/05-array-methods/12-reduce-object/_js.view/test.js
new file mode 100644
index 0000000000..e48ba138db
--- /dev/null
+++ b/1-js/05-data-types/05-array-methods/12-reduce-object/_js.view/test.js
@@ -0,0 +1,21 @@
+describe("groupById", function() {
+
+ it("creates an object grouped by id", function() {
+ let users = [
+ {id: 'john', name: "John Smith", age: 20},
+ {id: 'ann', name: "Ann Smith", age: 24},
+ {id: 'pete', name: "Pete Peterson", age: 31},
+ ];
+
+ assert.deepEqual(groupById(users), {
+ john: {id: 'john', name: "John Smith", age: 20},
+ ann: {id: 'ann', name: "Ann Smith", age: 24},
+ pete: {id: 'pete', name: "Pete Peterson", age: 31},
+ });
+ });
+
+ it("works with an empty array", function() {
+ users = [];
+ assert.deepEqual(groupById(users), {});
+ });
+});
diff --git a/1-js/05-data-types/05-array-methods/12-reduce-object/solution.md b/1-js/05-data-types/05-array-methods/12-reduce-object/solution.md
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/1-js/05-data-types/05-array-methods/12-reduce-object/task.md b/1-js/05-data-types/05-array-methods/12-reduce-object/task.md
new file mode 100644
index 0000000000..d3c8f8eb1a
--- /dev/null
+++ b/1-js/05-data-types/05-array-methods/12-reduce-object/task.md
@@ -0,0 +1,37 @@
+importance: 4
+
+---
+
+# Create keyed object from array
+
+Let's say we received an array of users in the form `{id:..., name:..., age... }`.
+
+Create a function `groupById(arr)` that creates an object from it, with `id` as the key, and array items as values.
+
+For example:
+
+```js
+let users = [
+ {id: 'john', name: "John Smith", age: 20},
+ {id: 'ann', name: "Ann Smith", age: 24},
+ {id: 'pete', name: "Pete Peterson", age: 31},
+];
+
+let usersById = groupById(users);
+
+/*
+// after the call we should have:
+
+usersById = {
+ john: {id: 'john', name: "John Smith", age: 20},
+ ann: {id: 'ann', name: "Ann Smith", age: 24},
+ pete: {id: 'pete', name: "Pete Peterson", age: 31},
+}
+*/
+```
+
+Such function is really handy when working with server data.
+
+In this task we assume that `id` is unique. There may be no two array items with the same `id`.
+
+Please use array `.reduce` method in the solution.
diff --git a/1-js/05-data-types/05-array-methods/4-sort-back/task.md b/1-js/05-data-types/05-array-methods/4-sort-back/task.md
index 382c207219..21de99287b 100644
--- a/1-js/05-data-types/05-array-methods/4-sort-back/task.md
+++ b/1-js/05-data-types/05-array-methods/4-sort-back/task.md
@@ -2,12 +2,20 @@ importance: 4
---
+<<<<<<< HEAD
# Сортировать в порядке по убыванию
+=======
+# Sort in decreasing order
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js
let arr = [5, 2, 1, -10, 8];
+<<<<<<< HEAD
// ... ваш код для сортировки по убыванию
+=======
+// ... your code to sort it in decreasing order
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
alert( arr ); // 8, 5, 2, 1, -10
```
diff --git a/1-js/05-data-types/05-array-methods/6-calculator-extendable/_js.view/solution.js b/1-js/05-data-types/05-array-methods/6-calculator-extendable/_js.view/solution.js
index 45ef1619da..f62452a5f7 100644
--- a/1-js/05-data-types/05-array-methods/6-calculator-extendable/_js.view/solution.js
+++ b/1-js/05-data-types/05-array-methods/6-calculator-extendable/_js.view/solution.js
@@ -10,14 +10,14 @@ function Calculator() {
let split = str.split(' '),
a = +split[0],
op = split[1],
- b = +split[2]
+ b = +split[2];
if (!this.methods[op] || isNaN(a) || isNaN(b)) {
return NaN;
}
return this.methods[op](a, b);
- }
+ };
this.addMethod = function(name, func) {
this.methods[name] = func;
diff --git a/1-js/05-data-types/05-array-methods/6-calculator-extendable/solution.md b/1-js/05-data-types/05-array-methods/6-calculator-extendable/solution.md
index a0f6cbf5ca..c57d69ccf7 100644
--- a/1-js/05-data-types/05-array-methods/6-calculator-extendable/solution.md
+++ b/1-js/05-data-types/05-array-methods/6-calculator-extendable/solution.md
@@ -1,5 +1,10 @@
+<<<<<<< HEAD
- Обратите внимание, как хранятся методы. Они просто добавляются к внутреннему объекту.
- Все тесты и числовые преобразования выполняются в методе `calculate`. В будущем он может быть расширен для поддержки более сложных выражений.
[js src="_js/solution.js"]
+=======
+- Please note how methods are stored. They are simply added to `this.methods` property.
+- All tests and numeric conversions are done in the `calculate` method. In future it may be extended to support more complex expressions.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
diff --git a/1-js/05-data-types/05-array-methods/article.md b/1-js/05-data-types/05-array-methods/article.md
index 227224cba4..ded54ac74d 100644
--- a/1-js/05-data-types/05-array-methods/article.md
+++ b/1-js/05-data-types/05-array-methods/article.md
@@ -36,7 +36,11 @@ alert( arr.length ); // 3
Поэтому для этого нужно использовать специальные методы.
+<<<<<<< HEAD
Метод [arr.splice(str)](mdn:js/Array/splice) – это универсальный "швейцарский нож" для работы с массивами. Умеет всё: добавлять, удалять и заменять элементы.
+=======
+The [arr.splice(start)](mdn:js/Array/splice) method is a swiss army knife for arrays. It can do everything: insert, remove and replace elements.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Его синтаксис:
@@ -159,6 +163,7 @@ arr.concat(arg1, arg2...)
```js run
let arr = [1, 2];
+<<<<<<< HEAD
// создать массив из: arr и [3,4]
alert( arr.concat([3, 4]) ); // 1,2,3,4
@@ -166,6 +171,15 @@ alert( arr.concat([3, 4]) ); // 1,2,3,4
alert( arr.concat([3, 4], [5, 6]) ); // 1,2,3,4,5,6
// создать массив из: arr и [3,4], потом добавить значения 5 и 6
+=======
+// create an array from: arr and [3,4]
+alert( arr.concat([3, 4]) ); // 1,2,3,4
+
+// create an array from: arr and [3,4] and [5,6]
+alert( arr.concat([3, 4], [5, 6]) ); // 1,2,3,4,5,6
+
+// create an array from: arr and [3,4], then add values 5 and 6
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
alert( arr.concat([3, 4], 5, 6) ); // 1,2,3,4,5,6
```
@@ -270,7 +284,11 @@ alert( arr.includes(NaN) );// true (верно)
Представьте, что у нас есть массив объектов. Как нам найти объект с определённым условием?
+<<<<<<< HEAD
Здесь пригодится метод [arr.find](mdn:js/Array/find).
+=======
+Here the [arr.find(fn)](mdn:js/Array/find) method comes in handy.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Его синтаксис таков:
```js
@@ -387,7 +405,11 @@ alert( arr ); // *!*1, 15, 2*/!*
**По умолчанию элементы сортируются как строки.**
+<<<<<<< HEAD
Буквально, элементы преобразуются в строки при сравнении. Для строк применяется лексикографический порядок, и действительно выходит, что `"2" > "15"`.
+=======
+Literally, all elements are converted to strings for comparisons. For strings, lexicographic ordering is applied and indeed `"2" > "15"`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Чтобы использовать наш собственный порядок сортировки, нам нужно предоставить функцию в качестве аргумента `arr.sort()`.
@@ -434,9 +456,14 @@ alert(arr); // *!*1, 2, 15*/!*
В процессе работы алгоритм может сравнивать элемент с другими по нескольку раз, но он старается сделать как можно меньше сравнений.
+<<<<<<< HEAD
````smart header="Функция сравнения может вернуть любое число"
На самом деле от функции сравнения требуется любое положительное число, чтобы сказать "больше", и отрицательное число, чтобы сказать "меньше".
+=======
+````smart header="A comparison function may return any number"
+Actually, a comparison function is only required to return a positive number to say "greater" and a negative number to say "less".
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Это позволяет писать более короткие функции:
@@ -449,8 +476,13 @@ alert(arr); // *!*1, 2, 15*/!*
```
````
+<<<<<<< HEAD
````smart header="Лучше использовать стрелочные функции"
Помните [стрелочные функции](info:arrow-functions-basics)? Можно использовать их здесь для того, чтобы сортировка выглядела более аккуратной:
+=======
+````smart header="Arrow functions for the best"
+Remember [arrow functions](info:arrow-functions-basics)? We can use them here for neater sorting:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js
arr.sort( (a, b) => a - b );
@@ -459,6 +491,22 @@ arr.sort( (a, b) => a - b );
Будет работать точно так же, как и более длинная версия выше.
````
+````smart header="Use `localeCompare` for strings"
+Remember [strings](info:string#correct-comparisons) comparison algorithm? It compares letters by their codes by default.
+
+For many alphabets, it's better to use `str.localeCompare` method to correctly sort letters, such as `Ö`.
+
+For example, let's sort a few countries in German:
+
+```js run
+let countries = ['Österreich', 'Andorra', 'Vietnam'];
+
+alert( countries.sort( (a, b) => a > b ? 1 : -1) ); // Andorra, Vietnam, Österreich (wrong)
+
+alert( countries.sort( (a, b) => a.localeCompare(b) ) ); // Andorra,Österreich,Vietnam (correct!)
+```
+````
+
### reverse
Метод [arr.reverse](mdn:js/Array/reverse) меняет порядок элементов в `arr` на обратный.
@@ -533,7 +581,7 @@ alert( str ); // Вася;Петя;Маша
Синтаксис:
```js
-let value = arr.reduce(function(previousValue, item, index, array) {
+let value = arr.reduce(function(accumulator, item, index, array) {
// ...
}, [initial]);
```
@@ -542,14 +590,27 @@ let value = arr.reduce(function(previousValue, item, index, array) {
Аргументы:
+<<<<<<< HEAD
- `previousValue` -- результат предыдущего вызова этой функции, равен `initial` при первом вызове (если передан `initial`),
- `item` -- очередной элемент массива,
- `index` -- его индекс,
- `array` -- сам массив.
+=======
+- `accumulator` -- is the result of the previous function call, equals `initial` the first time (if `initial` is provided).
+- `item` -- is the current array item.
+- `index` -- is its position.
+- `array` -- is the array.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
При вызове функции результат её вызова на предыдущем элементе массива передаётся как первый аргумент.
+<<<<<<< HEAD
Звучит сложновато, но всё становится проще, если думать о первом аргументе как "аккумулирующем" результат предыдущих вызовов функции. По окончании он становится результатом `reduce`.
+=======
+So, the first argument is essentially the accumulator that stores the combined result of all previous executions. And at the end it becomes the result of `reduce`.
+
+Sounds complicated?
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Этот метод проще всего понять на примере.
@@ -577,7 +638,7 @@ alert(result); // 15
В виде таблицы, где каждая строка –- вызов функции на очередном элементе массива:
-| |`sum`|`current`|`result`|
+| |`sum`|`current`|result|
|---|-----|---------|---------|
|первый вызов|`0`|`1`|`1`|
|второй вызов|`1`|`2`|`3`|
@@ -615,8 +676,12 @@ let arr = [];
arr.reduce((sum, current) => sum + current);
```
+<<<<<<< HEAD
Поэтому рекомендуется всегда указывать начальное значение.
+=======
+So it's advised to always specify the initial value.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Метод [arr.reduceRight](mdn:js/Array/reduceRight) работает аналогично, но проходит по массиву справа налево.
diff --git a/1-js/05-data-types/06-iterable/article.md b/1-js/05-data-types/06-iterable/article.md
index bf4fc1655a..42036ad43c 100644
--- a/1-js/05-data-types/06-iterable/article.md
+++ b/1-js/05-data-types/06-iterable/article.md
@@ -1,7 +1,11 @@
# Перебираемые объекты
+<<<<<<< HEAD
*Перебираемые* (или *итерируемые*) объекты - это концепция, которая позволяет использовать любой объект в цикле `for..of`.
+=======
+*Iterable* objects is a generalization of arrays. That's a concept that allows us to make any object useable in a `for..of` loop.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Конечно же, сами массивы являются перебираемыми объектами. Но есть и много других встроенных перебираемых объектов, например, строки.
@@ -11,7 +15,11 @@
Мы легко поймём принцип устройства перебираемых объектов, создав один из них.
+<<<<<<< HEAD
Например, у нас есть объект. Это не массив, но он выглядит подходящим для `for..of`.
+=======
+For instance, we have an object that is not an array, but looks suitable for `for..of`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Например, объект `range`, который представляет собой диапазон чисел:
@@ -141,7 +149,11 @@ for (let char of str) {
Чтобы понять устройство итераторов чуть глубже, давайте посмотрим, как их использовать явно.
+<<<<<<< HEAD
Мы будем перебирать строку точно так же, как цикл `for..of`, но вручную, прямыми вызовами. Нижеприведённый код получает строковый итератор и берёт из него значения:
+=======
+We'll iterate over a string in exactly the same way as `for..of`, but with direct calls. This code creates a string iterator and gets values from it "manually":
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js run
let str = "Hello";
@@ -149,7 +161,9 @@ let str = "Hello";
// делает то же самое, что и
// for (let char of str) alert(char);
+*!*
let iterator = str[Symbol.iterator]();
+*/!*
while (true) {
let result = iterator.next();
@@ -211,7 +225,11 @@ let arr = Array.from(arrayLike); // (*)
alert(arr.pop()); // World (метод работает)
```
+<<<<<<< HEAD
`Array.from` в строке `(*)` принимает объект, проверяет, является ли он итерируемым объектом или псевдомассивом, затем создаёт новый массив и копирует туда все элементы.
+=======
+`Array.from` at the line `(*)` takes the object, examines it for being an iterable or array-like, then makes a new array and copies all items to it.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
То же самое происходит с итерируемым объектом:
@@ -221,12 +239,20 @@ let arr = Array.from(range);
alert(arr); // 1,2,3,4,5 (преобразование массива через toString работает)
```
+<<<<<<< HEAD
Полный синтаксис `Array.from` позволяет указать необязательную "трансформирующую" функцию:
+=======
+The full syntax for `Array.from` also allows us to provide an optional "mapping" function:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js
Array.from(obj[, mapFn, thisArg])
```
+<<<<<<< HEAD
Необязательный второй аргумент может быть функцией, которая будет применена к каждому элементу перед добавлением в массив, а `thisArg` позволяет установить `this` для этой функции.
+=======
+The optional second argument `mapFn` can be a function that will be applied to each element before adding it to the array, and `thisArg` allows us to set `this` for it.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Например:
@@ -267,7 +293,11 @@ for (let char of str) {
alert(chars);
```
+<<<<<<< HEAD
...Но гораздо короче.
+=======
+...But it is shorter.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Мы можем даже создать `slice`, который поддерживает суррогатные пары:
@@ -289,12 +319,21 @@ alert( str.slice(1, 3) ); // мусор (две части различных с
Объекты, которые можно использовать в цикле `for..of`, называются *итерируемыми*.
+<<<<<<< HEAD
- Технически итерируемые объекты должны иметь метод `Symbol.iterator`.
- Результат вызова `obj[Symbol.iterator]` называется *итератором*. Он управляет процессом итерации.
- Итератор должен иметь метод `next()`, который возвращает объект `{done: Boolean, value: any}`, где `done:true` сигнализирует об окончании процесса итерации, в противном случае `value` - следующее значение.
- Метод `Symbol.iterator` автоматически вызывается циклом `for..of`, но можно вызвать его и напрямую.
- Встроенные итерируемые объекты, такие как строки или массивы, также реализуют метод `Symbol.iterator`.
- Строковой итератор знает про суррогатные пары.
+=======
+- Technically, iterables must implement the method named `Symbol.iterator`.
+ - The result of `obj[Symbol.iterator]` is called an *iterator*. It handles the further iteration process.
+ - An iterator must have the method named `next()` that returns an object `{done: Boolean, value: any}`, here `done:true` denotes the end of the iteration process, otherwise the `value` is the next value.
+- The `Symbol.iterator` method is called automatically by `for..of`, but we also can do it directly.
+- Built-in iterables like strings or arrays, also implement `Symbol.iterator`.
+- String iterator knows about surrogate pairs.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Объекты, имеющие индексированные свойства и `length`, называются *псевдомассивами*. Они также могут иметь другие свойства и методы, но у них нет встроенных методов массивов.
diff --git a/1-js/05-data-types/07-map-set/02-filter-anagrams/solution.md b/1-js/05-data-types/07-map-set/02-filter-anagrams/solution.md
index ca2e9723ec..09c3757b05 100644
--- a/1-js/05-data-types/07-map-set/02-filter-anagrams/solution.md
+++ b/1-js/05-data-types/07-map-set/02-filter-anagrams/solution.md
@@ -36,7 +36,7 @@ alert( aclean(arr) );
Для удобства, давайте разделим это на несколько строк:
```js
-let sorted = arr[i] // PAN
+let sorted = word // PAN
.toLowerCase() // pan
.split("") // ["p","a","n"]
.sort() // ["a","n","p"]
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 0f6ca1084d..6a5d809e06 100644
--- a/1-js/05-data-types/07-map-set/article.md
+++ b/1-js/05-data-types/07-map-set/article.md
@@ -41,7 +41,17 @@ alert(map.size); // 3
Как мы видим, в отличие от объектов, ключи не были приведены к строкам. Можно использовать любые типы данных для ключей.
+<<<<<<< HEAD
**Map может использовать объекты в качестве ключей.**
+=======
+```smart header="`map[key]` isn't the right way to use a `Map`"
+Although `map[key]` also works, e.g. we can set `map[key] = 2`, this is treating `map` as a plain JavaScript object, so it implies all corresponding limitations (no object keys and so on).
+
+So we should use `map` methods: `set`, `get` and so on.
+```
+
+**Map can also use objects as keys.**
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Например:
@@ -189,7 +199,11 @@ let prices = Object.fromEntries([
alert(prices.orange); // 2
```
+<<<<<<< HEAD
Мы можем использовать `Object.fromEntries`, чтобы получить обычный объект из `Map`.
+=======
+We can use `Object.fromEntries` to get a plain object from `Map`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
К примеру, у нас данные в `Map`, но их нужно передать в сторонний код, который ожидает обычный объект.
@@ -211,9 +225,13 @@ let obj = Object.fromEntries(map.entries()); // make a plain object (*)
alert(obj.orange); // 2
```
+<<<<<<< HEAD
Вызов `map.entries()` возвращает массив пар ключ/значение, как раз в нужном формате для `Object.fromEntries`.
Мы могли бы написать строку `(*)` ещё короче:
+=======
+A call to `map.entries()` returns an iterable of key/value pairs, exactly in the right format for `Object.fromEntries`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js
let obj = Object.fromEntries(map); // убрать .entries()
diff --git a/1-js/05-data-types/08-weakmap-weakset/01-recipients-read/solution.md b/1-js/05-data-types/08-weakmap-weakset/01-recipients-read/solution.md
index 8032287a7d..25c04d50a0 100644
--- a/1-js/05-data-types/08-weakmap-weakset/01-recipients-read/solution.md
+++ b/1-js/05-data-types/08-weakmap-weakset/01-recipients-read/solution.md
@@ -1,6 +1,6 @@
Можно хранить прочитанные сообщения в `WeakSet`:
-```js
+```js run
let messages = [
{text: "Hello", from: "John"},
{text: "How goes?", from: "John"},
diff --git a/1-js/05-data-types/08-weakmap-weakset/01-recipients-read/task.md b/1-js/05-data-types/08-weakmap-weakset/01-recipients-read/task.md
index 215aa27cfd..41317b1d98 100644
--- a/1-js/05-data-types/08-weakmap-weakset/01-recipients-read/task.md
+++ b/1-js/05-data-types/08-weakmap-weakset/01-recipients-read/task.md
@@ -16,7 +16,11 @@ let messages = [
У вас есть к ним доступ, но управление этим массивом происходит где-то ещё. Добавляются новые сообщения и удаляются старые, и вы не знаете в какой момент это может произойти.
+<<<<<<< HEAD
Имея такую вводную информацию, решите, какую структуру данных вы могли бы использовать для ответа на вопрос "было ли сообщение прочитано?". Структура должна быть подходящей, чтобы можно было однозначно сказать, было ли прочитано это сообщение для каждого объекта сообщения.
+=======
+Now, which data structure could you use to store information about whether the message "has been read"? The structure must be well-suited to give the answer "was it read?" for the given message object.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
P.S. Когда сообщение удаляется из массива `messages`, оно должно также исчезать из структуры данных.
diff --git a/1-js/05-data-types/08-weakmap-weakset/article.md b/1-js/05-data-types/08-weakmap-weakset/article.md
index bfd0db0956..3114d6e899 100644
--- a/1-js/05-data-types/08-weakmap-weakset/article.md
+++ b/1-js/05-data-types/08-weakmap-weakset/article.md
@@ -142,7 +142,11 @@ function countUser(user) {
// 📁 main.js
let john = { name: "John" };
+<<<<<<< HEAD
countUser(john); //ведём подсчёт посещений
+=======
+countUser(john); // count his visits
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
// пользователь покинул нас
john = null;
diff --git a/1-js/05-data-types/09-keys-values-entries/article.md b/1-js/05-data-types/09-keys-values-entries/article.md
index b927527d80..065f55a3fe 100644
--- a/1-js/05-data-types/09-keys-values-entries/article.md
+++ b/1-js/05-data-types/09-keys-values-entries/article.md
@@ -75,9 +75,13 @@ for (let value of Object.values(user)) {
Если мы хотели бы их применить, то можно использовать `Object.entries` с последующим вызовом `Object.fromEntries`:
+<<<<<<< HEAD
1. Вызов `Object.entries(obj)` возвращает массив пар ключ/значение для `obj`.
2. На нём вызываем методы массива, например, `map`.
3. Используем `Object.fromEntries(array)` на результате, чтобы преобразовать его обратно в объект.
+=======
+If we'd like to apply them, then we can use `Object.entries` followed by `Object.fromEntries`:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Например, у нас есть объект с ценами, и мы хотели бы их удвоить:
@@ -98,6 +102,10 @@ let doublePrices = Object.fromEntries(
alert(doublePrices.meat); // 8
```
+<<<<<<< HEAD
Это может выглядеть сложным на первый взгляд, но становится лёгким для понимания после нескольких раз использования.
Можно делать и более сложные "однострочные" преобразования таким путём. Важно только сохранять баланс, чтобы код при этом был достаточно простым для понимания.
+=======
+It may look difficult from the first sight, but becomes easy to understand after you use it once or twice. We can make powerful chains of transforms this way.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
diff --git a/1-js/05-data-types/10-destructuring-assignment/article.md b/1-js/05-data-types/10-destructuring-assignment/article.md
index 8e86e9dfd5..e9c468079c 100644
--- a/1-js/05-data-types/10-destructuring-assignment/article.md
+++ b/1-js/05-data-types/10-destructuring-assignment/article.md
@@ -120,7 +120,30 @@ for (let [key, value] of user) {
}
```
````
+<<<<<<< HEAD
### Остаточные параметры "..."
+=======
+
+```smart header="Swap variables trick"
+A well-known trick for swapping values of two variables:
+
+```js run
+let guest = "Jane";
+let admin = "Pete";
+
+// Swap values: make guest=Pete, admin=Jane
+[guest, admin] = [admin, guest];
+
+alert(`${guest} ${admin}`); // Pete Jane (successfully swapped!)
+```
+
+Here we create a temporary array of two variables and immediately destructure it in swapped order.
+
+We can swap more than two variables this way.
+
+
+### The rest '...'
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Если мы хотим не просто получить первые значения, но и собрать все остальные, то мы можем добавить ещё один параметр, который получает остальные значения, используя оператор "остаточные параметры" -- троеточие (`"..."`):
@@ -355,7 +378,11 @@ let title, width, height;
}
```
+<<<<<<< HEAD
Так что здесь JavaScript считает, что видит блок кода, отсюда и ошибка. На самом-то деле у нас деструктуризация.
+=======
+So here JavaScript assumes that we have a code block, that's why there's an error. We want destructuring instead.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Чтобы показать JavaScript, что это не блок кода, мы можем заключить выражение в скобки `(...)`:
diff --git a/1-js/05-data-types/11-date/1-new-date/solution.md b/1-js/05-data-types/11-date/1-new-date/solution.md
index c479b01055..d23af60396 100644
--- a/1-js/05-data-types/11-date/1-new-date/solution.md
+++ b/1-js/05-data-types/11-date/1-new-date/solution.md
@@ -2,7 +2,17 @@
Поэтому февраль обозначается числом 1.
+Here's an example with numbers as date components:
+
+```js run
+//new Date(year, month, date, hour, minute, second, millisecond)
+let d1 = new Date(2012, 1, 20, 3, 12);
+alert( d1 );
+```
+We could also create a date from a string, like this:
+
```js run
-let d = new Date(2012, 1, 20, 3, 12);
-alert( d );
+//new Date(datastring)
+let d2 = new Date("February 20, 2012 03:12:00");
+alert( d2 );
```
diff --git a/1-js/05-data-types/11-date/6-get-seconds-today/solution.md b/1-js/05-data-types/11-date/6-get-seconds-today/solution.md
index 05412bd44c..cd9a566346 100644
--- a/1-js/05-data-types/11-date/6-get-seconds-today/solution.md
+++ b/1-js/05-data-types/11-date/6-get-seconds-today/solution.md
@@ -23,4 +23,6 @@ function getSecondsToday() {
let d = new Date();
return d.getHours() * 3600 + d.getMinutes() * 60 + d.getSeconds();
}
+
+alert( getSecondsToday() );
```
diff --git a/1-js/05-data-types/11-date/6-get-seconds-today/task.md b/1-js/05-data-types/11-date/6-get-seconds-today/task.md
index 46df738e26..7e92b92389 100644
--- a/1-js/05-data-types/11-date/6-get-seconds-today/task.md
+++ b/1-js/05-data-types/11-date/6-get-seconds-today/task.md
@@ -2,11 +2,19 @@ importance: 5
---
+<<<<<<< HEAD
# Сколько сегодня прошло секунд?
+=======
+# How many seconds have passed today?
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Напишите функцию `getSecondsToday()`, возвращающую количество секунд с начала сегодняшнего дня.
+<<<<<<< HEAD
Например, если сейчас `10:00`, и не было перехода на зимнее/летнее время, то:
+=======
+For instance, if now were `10:00 am`, and there was no daylight savings shift, then:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js
getSecondsToday() == 36000 // (3600 * 10)
diff --git a/1-js/05-data-types/11-date/8-format-date-relative/solution.md b/1-js/05-data-types/11-date/8-format-date-relative/solution.md
index a98fe45c8a..76c98c29b0 100644
--- a/1-js/05-data-types/11-date/8-format-date-relative/solution.md
+++ b/1-js/05-data-types/11-date/8-format-date-relative/solution.md
@@ -40,7 +40,11 @@ alert( formatDate(new Date(new Date - 30 * 1000)) ); // "30 сек. назад"
alert( formatDate(new Date(new Date - 5 * 60 * 1000)) ); // "5 мин. назад"
+<<<<<<< HEAD
// вчерашняя дата вроде 31.12.2016, 20:00
+=======
+// yesterday's date like 31.12.2016 20:00
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
alert( formatDate(new Date(new Date - 86400 * 1000)) );
```
diff --git a/1-js/05-data-types/11-date/8-format-date-relative/task.md b/1-js/05-data-types/11-date/8-format-date-relative/task.md
index 0ecf640e2c..491f744b32 100644
--- a/1-js/05-data-types/11-date/8-format-date-relative/task.md
+++ b/1-js/05-data-types/11-date/8-format-date-relative/task.md
@@ -20,6 +20,10 @@ alert( formatDate(new Date(new Date - 30 * 1000)) ); // "30 сек. назад"
alert( formatDate(new Date(new Date - 5 * 60 * 1000)) ); // "5 мин. назад"
+<<<<<<< HEAD
// вчерашняя дата вроде 31.12.2016, 20:00
+=======
+// yesterday's date like 31.12.16 20:00
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
alert( formatDate(new Date(new Date - 86400 * 1000)) );
```
diff --git a/1-js/05-data-types/11-date/article.md b/1-js/05-data-types/11-date/article.md
index 1ced209f5f..fd8fa349f2 100644
--- a/1-js/05-data-types/11-date/article.md
+++ b/1-js/05-data-types/11-date/article.md
@@ -33,6 +33,7 @@
Это -- легковесное численное представление даты. Из таймстампа всегда можно получить дату с помощью `new Date(timestamp)` и преобразовать существующий объект `Date` в таймстамп, используя метод `date.getTime()` (см. ниже).
+<<<<<<< HEAD
Датам до 1 января 1970 будут соответствовать отрицательные таймстампы, например:
```js run
// 31 декабря 1969 года
@@ -40,6 +41,15 @@
alert( Dec31_1969 );
```
+=======
+ Dates before 01.01.1970 have negative timestamps, e.g.:
+ ```js run
+ // 31 Dec 1969
+ let Dec31_1969 = new Date(-24 * 3600 * 1000);
+ alert( Dec31_1969 );
+ ```
+
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
`new Date(datestring)`
: Если аргумент всего один, и это строка, то из неё "прочитывается" дата. Алгоритм разбора - такой же, как в `Date.parse`, который мы рассмотрим позже.
@@ -65,8 +75,13 @@
Например:
```js
+<<<<<<< HEAD
new Date(2011, 0, 1, 0, 0, 0, 0); // // 1 Jan 2011, 00:00:00
new Date(2011, 0, 1); // то же самое, так как часы и проч. равны 0
+=======
+ new Date(2011, 0, 1, 0, 0, 0, 0); // 1 Jan 2011, 00:00:00
+ new Date(2011, 0, 1); // the same, hours etc are 0 by default
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```
Минимальная точность – 1 мс (1/1000 секунды):
@@ -123,8 +138,13 @@ alert( date.getUTCHours() );
[getTime()](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Date/getTime)
: Для заданной даты возвращает таймстамп - количество миллисекунд, прошедших с 1 января 1970 года UTC+0.
+<<<<<<< HEAD
[getTimezoneOffset()](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset)
: Возвращает разницу в минутах между местным часовым поясом и UTC:
+=======
+[getTimezoneOffset()](mdn:js/Date/getTimezoneOffset)
+: Returns the difference between UTC and the local time zone, in minutes:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js run
// если вы в часовом поясе UTC-1, то выводится 60
diff --git a/1-js/05-data-types/12-json/article.md b/1-js/05-data-types/12-json/article.md
index 3507de1542..b9c0b8954f 100644
--- a/1-js/05-data-types/12-json/article.md
+++ b/1-js/05-data-types/12-json/article.md
@@ -424,9 +424,9 @@ alert( numbers[1] ); // 1
Или для вложенных объектов:
```js run
-let user = '{ "name": "John", "age": 35, "isAdmin": false, "friends": [0,1,2,3] }';
+let userData = '{ "name": "John", "age": 35, "isAdmin": false, "friends": [0,1,2,3] }';
-user = JSON.parse(user);
+let user = JSON.parse(userData);
alert( user.friends[1] ); // 1
```
diff --git a/1-js/06-advanced-functions/01-recursion/article.md b/1-js/06-advanced-functions/01-recursion/article.md
index 68456a9f13..4a4963c7df 100644
--- a/1-js/06-advanced-functions/01-recursion/article.md
+++ b/1-js/06-advanced-functions/01-recursion/article.md
@@ -184,7 +184,17 @@ alert( pow(2, 3) );
Новый контекст выполнения находится на вершине стека (и выделен жирным), а предыдущие запомненные контексты -- под ним.
+<<<<<<< HEAD
Когда выполнение подвызова закончится, можно будет легко вернуться назад, потому что контекст сохраняет как переменные, так и точное место кода, в котором он остановился. Слово "строка" на рисунках условно, на самом деле запоминается более точное место в цепочке команд.
+=======
+When we finish the subcall -- it is easy to resume the previous context, because it keeps both variables and the exact place of the code where it stopped.
+
+```smart
+Here in the picture we use the word "line", as our example there's only one subcall in line, but generally a single line of code may contain multiple subcalls, like `pow(…) + pow(…) + somethingElse(…)`.
+
+So it would be more precise to say that the execution resumes "immediately after the subcall".
+```
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
### pow(2, 1)
@@ -295,7 +305,7 @@ let company = {
salary: 1000
}, {
name: 'Alice',
- salary: 600
+ salary: 1600
}],
development: {
@@ -342,8 +352,13 @@ let company = {
```js run
+<<<<<<< HEAD
let company = { // тот же самый объект, сжатый для краткости
sales: [{name: 'John', salary: 1000}, {name: 'Alice', salary: 600 }],
+=======
+let company = { // the same object, compressed for brevity
+ sales: [{name: 'John', salary: 1000}, {name: 'Alice', salary: 1600 }],
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
development: {
sites: [{name: 'Peter', salary: 2000}, {name: 'Alex', salary: 1800 }],
internals: [{name: 'Jack', salary: 1300}]
@@ -365,7 +380,7 @@ function sumSalaries(department) {
}
*/!*
-alert(sumSalaries(company)); // 6700
+alert(sumSalaries(company)); // 7700
```
Код краток и прост для понимания (надеюсь?). В этом сила рекурсии. Она работает на любом уровне вложенности отделов.
@@ -452,9 +467,14 @@ let list = { value: 1 };
list.next = { value: 2 };
list.next.next = { value: 3 };
list.next.next.next = { value: 4 };
+list.next.next.next.next = null;
```
+<<<<<<< HEAD
Здесь мы можем ещё лучше увидеть, что есть несколько объектов, каждый из которых имеет `value` и `next`, указывающий на соседа. Переменная `list` является первым объектом в цепочке, поэтому, следуя по указателям `next` из неё, мы можем попасть в любой элемент.
+=======
+Here we can even more clearly see that there are multiple objects, each one has the `value` and `next` pointing to the neighbour. The `list` variable is the first object in the chain, so following `next` pointers from it we can reach any element.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Список можно легко разделить на несколько частей и впоследствии объединить обратно:
diff --git a/1-js/06-advanced-functions/02-rest-parameters-spread-operator/article.md b/1-js/06-advanced-functions/02-rest-parameters-spread/article.md
similarity index 70%
rename from 1-js/06-advanced-functions/02-rest-parameters-spread-operator/article.md
rename to 1-js/06-advanced-functions/02-rest-parameters-spread/article.md
index 49baf99431..e60243e8f9 100644
--- a/1-js/06-advanced-functions/02-rest-parameters-spread-operator/article.md
+++ b/1-js/06-advanced-functions/02-rest-parameters-spread/article.md
@@ -1,4 +1,8 @@
+<<<<<<< HEAD:1-js/06-advanced-functions/02-rest-parameters-spread-operator/article.md
# Остаточные параметры и оператор расширения
+=======
+# Rest parameters and spread syntax
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/06-advanced-functions/02-rest-parameters-spread/article.md
Многие встроенные функции JavaScript поддерживают произвольное количество аргументов.
@@ -122,7 +126,11 @@ f(1); // 1
````
+<<<<<<< HEAD:1-js/06-advanced-functions/02-rest-parameters-spread-operator/article.md
## Оператор расширения [#spread-operator]
+=======
+## Spread syntax [#spread-syntax]
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/06-advanced-functions/02-rest-parameters-spread/article.md
Мы узнали, как получить массив из списка параметров.
@@ -148,7 +156,11 @@ alert( Math.max(arr) ); // NaN
Конечно, мы можем вводить числа вручную : `Math.max(arr[0], arr[1], arr[2])`. Но, во-первых, это плохо выглядит, а, во-вторых, мы не всегда знаем, сколько будет аргументов. Их может быть как очень много, так и не быть совсем.
+<<<<<<< HEAD:1-js/06-advanced-functions/02-rest-parameters-spread-operator/article.md
И тут нам поможет *оператор расширения*. Он похож на остаточные параметры – тоже использует `...`, но делает совершенно противоположное.
+=======
+*Spread syntax* to the rescue! It looks similar to rest parameters, also using `...`, but does quite the opposite.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/06-advanced-functions/02-rest-parameters-spread/article.md
Когда `...arr` используется при вызове функции, он "расширяет" перебираемый объект `arr` в список аргументов.
@@ -169,7 +181,12 @@ let arr2 = [8, 3, -8, 1];
alert( Math.max(...arr1, ...arr2) ); // 8
```
+<<<<<<< HEAD:1-js/06-advanced-functions/02-rest-parameters-spread-operator/article.md
Мы даже можем комбинировать оператор расширения с обычными значениями:
+=======
+We can even combine the spread syntax with normal values:
+
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/06-advanced-functions/02-rest-parameters-spread/article.md
```js run
let arr1 = [1, -2, 3, 4];
@@ -178,7 +195,11 @@ let arr2 = [8, 3, -8, 1];
alert( Math.max(1, ...arr1, 2, ...arr2, 25) ); // 25
```
+<<<<<<< HEAD:1-js/06-advanced-functions/02-rest-parameters-spread-operator/article.md
Оператор расширения можно использовать и для слияния массивов:
+=======
+Also, the spread syntax can be used to merge arrays:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/06-advanced-functions/02-rest-parameters-spread/article.md
```js run
let arr = [3, 5, 1];
@@ -191,9 +212,15 @@ let merged = [0, ...arr, 2, ...arr2];
alert(merged); // 0,3,5,1,2,8,9,15 (0, затем arr, затем 2, в конце arr2)
```
+<<<<<<< HEAD:1-js/06-advanced-functions/02-rest-parameters-spread-operator/article.md
В примерах выше мы использовали массив, чтобы продемонстрировать свойства оператора расширения, но он работает с любым перебираемым объектом.
Например, оператор расширения подойдёт для того, чтобы превратить строку в массив символов:
+=======
+In the examples above we used an array to demonstrate the spread syntax, but any iterable will do.
+
+For instance, here we use the spread syntax to turn the string into array of characters:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/06-advanced-functions/02-rest-parameters-spread/article.md
```js run
let str = "Привет";
@@ -201,7 +228,11 @@ let str = "Привет";
alert( [...str] ); // П,р,и,в,е,т
```
+<<<<<<< HEAD:1-js/06-advanced-functions/02-rest-parameters-spread-operator/article.md
Посмотрим, что происходит. Под капотом оператор расширения использует итераторы, чтобы перебирать элементы. Так же, как это делает `for..of`.
+=======
+The spread syntax internally uses iterators to gather elements, the same way as `for..of` does.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/06-advanced-functions/02-rest-parameters-spread/article.md
Цикл `for..of` перебирает строку как последовательность символов, поэтому из `...str` получается `"П", "р", "и", "в", "е", "т"`. Получившиеся символы собираются в массив при помощи стандартного объявления массива: `[...str]`.
@@ -218,25 +249,91 @@ alert( Array.from(str) ); // П,р,и,в,е,т
Но между `Array.from(obj)` и `[...obj]` есть разница:
+<<<<<<< HEAD:1-js/06-advanced-functions/02-rest-parameters-spread-operator/article.md
- `Array.from` работает как с псевдомассивами, так и с итерируемыми объектами
- Оператор расширения работает только с итерируемыми объектами
+=======
+- `Array.from` operates on both array-likes and iterables.
+- The spread syntax works only with iterables.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/06-advanced-functions/02-rest-parameters-spread/article.md
Выходит, что если нужно сделать из чего угодно массив, то `Array.from` — более универсальный метод.
+<<<<<<< HEAD:1-js/06-advanced-functions/02-rest-parameters-spread-operator/article.md
## Итого
Когда мы видим `"..."` в коде, это могут быть как остаточные параметры, так и оператор расширения.
+=======
+## Get a new copy of an array/object
+
+Remember when we talked about `Object.assign()` [in the past](info:object-copy#cloning-and-merging-object-assign)?
+
+It is possible to do the same thing with the spread syntax.
+
+```js run
+let arr = [1, 2, 3];
+let arrCopy = [...arr]; // spread the array into a list of parameters
+ // then put the result into a new array
+
+// do the arrays have the same contents?
+alert(JSON.stringify(arr) === JSON.stringify(arrCopy)); // true
+
+// are the arrays equal?
+alert(arr === arrCopy); // false (not same reference)
+
+// modifying our initial array does not modify the copy:
+arr.push(4);
+alert(arr); // 1, 2, 3, 4
+alert(arrCopy); // 1, 2, 3
+```
+
+Note that it is possible to do the same thing to make a copy of an object:
+
+```js run
+let obj = { a: 1, b: 2, c: 3 };
+let objCopy = { ...obj }; // spread the object into a list of parameters
+ // then return the result in a new object
+
+// do the objects have the same contents?
+alert(JSON.stringify(obj) === JSON.stringify(objCopy)); // true
+
+// are the objects equal?
+alert(obj === objCopy); // false (not same reference)
+
+// modifying our initial object does not modify the copy:
+obj.d = 4;
+alert(JSON.stringify(obj)); // {"a":1,"b":2,"c":3,"d":4}
+alert(JSON.stringify(objCopy)); // {"a":1,"b":2,"c":3}
+```
+
+This way of copying an object is much shorter than `let objCopy = Object.assign({}, obj);` or for an array `let arrCopy = Object.assign([], arr);` so we prefer to use it whenever we can.
+
+
+## Summary
+
+When we see `"..."` in the code, it is either rest parameters or the spread syntax.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/06-advanced-functions/02-rest-parameters-spread/article.md
Как отличить их друг от друга:
+<<<<<<< HEAD:1-js/06-advanced-functions/02-rest-parameters-spread-operator/article.md
- Если `...` располагается в конце списка аргументов функции, то это "остаточные параметры". Он собирает остальные неуказанные аргументы и делает из них массив.
- Если `...` встретился в вызове функции или где-либо ещё, то это "оператор расширения". Он извлекает элементы из массива.
+=======
+- When `...` is at the end of function parameters, it's "rest parameters" and gathers the rest of the list of arguments into an array.
+- When `...` occurs in a function call or alike, it's called a "spread syntax" and expands an array into a list.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/06-advanced-functions/02-rest-parameters-spread/article.md
Полезно запомнить:
+<<<<<<< HEAD:1-js/06-advanced-functions/02-rest-parameters-spread-operator/article.md
- Остаточные параметры используются, чтобы создавать новые функции с неопределённым числом аргументов.
- С помощью оператора расширения можно вставить массив в функцию, которая по умолчанию работает с обычным списком аргументов.
+=======
+- Rest parameters are used to create functions that accept any number of arguments.
+- The spread syntax is used to pass an array to functions that normally require a list of many arguments.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/06-advanced-functions/02-rest-parameters-spread/article.md
Вместе эти конструкции помогают легко преобразовывать наборы значений в массивы и обратно.
diff --git a/1-js/06-advanced-functions/03-closure/1-closure-latest-changes/solution.md b/1-js/06-advanced-functions/03-closure/1-closure-latest-changes/solution.md
new file mode 100644
index 0000000000..7cbd85ab75
--- /dev/null
+++ b/1-js/06-advanced-functions/03-closure/1-closure-latest-changes/solution.md
@@ -0,0 +1,5 @@
+The answer is: **Pete**.
+
+A function gets outer variables as they are now, it uses the most recent values.
+
+Old variable values are not saved anywhere. When a function wants a variable, it takes the current value from its own Lexical Environment or the outer one.
diff --git a/1-js/06-advanced-functions/03-closure/1-closure-latest-changes/task.md b/1-js/06-advanced-functions/03-closure/1-closure-latest-changes/task.md
new file mode 100644
index 0000000000..819189773c
--- /dev/null
+++ b/1-js/06-advanced-functions/03-closure/1-closure-latest-changes/task.md
@@ -0,0 +1,23 @@
+importance: 5
+
+---
+
+# Does a function pickup latest changes?
+
+The function sayHi uses an external variable name. When the function runs, which value is it going to use?
+
+```js
+let name = "John";
+
+function sayHi() {
+ alert("Hi, " + name);
+}
+
+name = "Pete";
+
+sayHi(); // what will it show: "John" or "Pete"?
+```
+
+Such situations are common both in browser and server-side development. A function may be scheduled to execute later than it is created, for instance after a user action or a network request.
+
+So, the question is: does it pick up the latest changes?
diff --git a/1-js/06-advanced-functions/03-closure/8-make-army/_js.view/solution.js b/1-js/06-advanced-functions/03-closure/10-make-army/_js.view/solution.js
similarity index 100%
rename from 1-js/06-advanced-functions/03-closure/8-make-army/_js.view/solution.js
rename to 1-js/06-advanced-functions/03-closure/10-make-army/_js.view/solution.js
diff --git a/1-js/06-advanced-functions/03-closure/8-make-army/_js.view/source.js b/1-js/06-advanced-functions/03-closure/10-make-army/_js.view/source.js
similarity index 100%
rename from 1-js/06-advanced-functions/03-closure/8-make-army/_js.view/source.js
rename to 1-js/06-advanced-functions/03-closure/10-make-army/_js.view/source.js
diff --git a/1-js/06-advanced-functions/03-closure/8-make-army/_js.view/test.js b/1-js/06-advanced-functions/03-closure/10-make-army/_js.view/test.js
similarity index 100%
rename from 1-js/06-advanced-functions/03-closure/8-make-army/_js.view/test.js
rename to 1-js/06-advanced-functions/03-closure/10-make-army/_js.view/test.js
diff --git a/1-js/06-advanced-functions/03-closure/8-make-army/lexenv-makearmy.svg b/1-js/06-advanced-functions/03-closure/10-make-army/lexenv-makearmy.svg
similarity index 100%
rename from 1-js/06-advanced-functions/03-closure/8-make-army/lexenv-makearmy.svg
rename to 1-js/06-advanced-functions/03-closure/10-make-army/lexenv-makearmy.svg
diff --git a/1-js/06-advanced-functions/03-closure/8-make-army/solution.md b/1-js/06-advanced-functions/03-closure/10-make-army/solution.md
similarity index 100%
rename from 1-js/06-advanced-functions/03-closure/8-make-army/solution.md
rename to 1-js/06-advanced-functions/03-closure/10-make-army/solution.md
diff --git a/1-js/06-advanced-functions/03-closure/8-make-army/task.md b/1-js/06-advanced-functions/03-closure/10-make-army/task.md
similarity index 78%
rename from 1-js/06-advanced-functions/03-closure/8-make-army/task.md
rename to 1-js/06-advanced-functions/03-closure/10-make-army/task.md
index 130909bb5e..41b94336c0 100644
--- a/1-js/06-advanced-functions/03-closure/8-make-army/task.md
+++ b/1-js/06-advanced-functions/03-closure/10-make-army/task.md
@@ -31,5 +31,9 @@ army[5](); // и у 5-го стрелка тоже будет номер 10
// ... у всех стрелков будет номер 10, вместо 0, 1, 2, 3...
```
+<<<<<<< HEAD:1-js/06-advanced-functions/03-closure/8-make-army/task.md
Почему у всех стрелков одинаковые номера? Почините код, чтобы он работал как задумано.
+=======
+Why do all of the shooters show the same value? Fix the code so that they work as intended.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:1-js/06-advanced-functions/03-closure/10-make-army/task.md
diff --git a/1-js/06-advanced-functions/03-closure/lexenv-nested-work.svg b/1-js/06-advanced-functions/03-closure/2-closure-variable-access/lexenv-nested-work.svg
similarity index 100%
rename from 1-js/06-advanced-functions/03-closure/lexenv-nested-work.svg
rename to 1-js/06-advanced-functions/03-closure/2-closure-variable-access/lexenv-nested-work.svg
diff --git a/1-js/06-advanced-functions/03-closure/2-closure-variable-access/solution.md b/1-js/06-advanced-functions/03-closure/2-closure-variable-access/solution.md
new file mode 100644
index 0000000000..0a522132fe
--- /dev/null
+++ b/1-js/06-advanced-functions/03-closure/2-closure-variable-access/solution.md
@@ -0,0 +1,9 @@
+The answer is: **Pete**.
+
+The `work()` function in the code below gets `name` from the place of its origin through the outer lexical environment reference:
+
+
+
+So, the result is `"Pete"` here.
+
+But if there were no `let name` in `makeWorker()`, then the search would go outside and take the global variable as we can see from the chain above. In that case the result would be `"John"`.
diff --git a/1-js/06-advanced-functions/03-closure/2-closure-variable-access/task.md b/1-js/06-advanced-functions/03-closure/2-closure-variable-access/task.md
new file mode 100644
index 0000000000..d12a385c81
--- /dev/null
+++ b/1-js/06-advanced-functions/03-closure/2-closure-variable-access/task.md
@@ -0,0 +1,29 @@
+importance: 5
+
+---
+
+# Which variables are available?
+
+The function `makeWorker` below makes another function and returns it. That new function can be called from somewhere else.
+
+Will it have access to the outer variables from its creation place, or the invocation place, or both?
+
+```js
+function makeWorker() {
+ let name = "Pete";
+
+ return function() {
+ alert(name);
+ };
+}
+
+let name = "John";
+
+// create a function
+let work = makeWorker();
+
+// call it
+work(); // what will it show?
+```
+
+Which value it will show? "Pete" or "John"?
diff --git a/1-js/06-advanced-functions/03-closure/1-counter-independent/solution.md b/1-js/06-advanced-functions/03-closure/3-counter-independent/solution.md
similarity index 100%
rename from 1-js/06-advanced-functions/03-closure/1-counter-independent/solution.md
rename to 1-js/06-advanced-functions/03-closure/3-counter-independent/solution.md
diff --git a/1-js/06-advanced-functions/03-closure/1-counter-independent/task.md b/1-js/06-advanced-functions/03-closure/3-counter-independent/task.md
similarity index 100%
rename from 1-js/06-advanced-functions/03-closure/1-counter-independent/task.md
rename to 1-js/06-advanced-functions/03-closure/3-counter-independent/task.md
diff --git a/1-js/06-advanced-functions/03-closure/2-counter-object-independent/solution.md b/1-js/06-advanced-functions/03-closure/4-counter-object-independent/solution.md
similarity index 100%
rename from 1-js/06-advanced-functions/03-closure/2-counter-object-independent/solution.md
rename to 1-js/06-advanced-functions/03-closure/4-counter-object-independent/solution.md
diff --git a/1-js/06-advanced-functions/03-closure/2-counter-object-independent/task.md b/1-js/06-advanced-functions/03-closure/4-counter-object-independent/task.md
similarity index 100%
rename from 1-js/06-advanced-functions/03-closure/2-counter-object-independent/task.md
rename to 1-js/06-advanced-functions/03-closure/4-counter-object-independent/task.md
diff --git a/1-js/06-advanced-functions/03-closure/3-function-in-if/solution.md b/1-js/06-advanced-functions/03-closure/5-function-in-if/solution.md
similarity index 100%
rename from 1-js/06-advanced-functions/03-closure/3-function-in-if/solution.md
rename to 1-js/06-advanced-functions/03-closure/5-function-in-if/solution.md
diff --git a/1-js/06-advanced-functions/03-closure/3-function-in-if/task.md b/1-js/06-advanced-functions/03-closure/5-function-in-if/task.md
similarity index 100%
rename from 1-js/06-advanced-functions/03-closure/3-function-in-if/task.md
rename to 1-js/06-advanced-functions/03-closure/5-function-in-if/task.md
diff --git a/1-js/06-advanced-functions/03-closure/4-closure-sum/solution.md b/1-js/06-advanced-functions/03-closure/6-closure-sum/solution.md
similarity index 100%
rename from 1-js/06-advanced-functions/03-closure/4-closure-sum/solution.md
rename to 1-js/06-advanced-functions/03-closure/6-closure-sum/solution.md
diff --git a/1-js/06-advanced-functions/03-closure/4-closure-sum/task.md b/1-js/06-advanced-functions/03-closure/6-closure-sum/task.md
similarity index 100%
rename from 1-js/06-advanced-functions/03-closure/4-closure-sum/task.md
rename to 1-js/06-advanced-functions/03-closure/6-closure-sum/task.md
diff --git a/1-js/06-advanced-functions/03-closure/7-let-scope/solution.md b/1-js/06-advanced-functions/03-closure/7-let-scope/solution.md
new file mode 100644
index 0000000000..346e4060a3
--- /dev/null
+++ b/1-js/06-advanced-functions/03-closure/7-let-scope/solution.md
@@ -0,0 +1,40 @@
+The result is: **error**.
+
+Try running it:
+
+```js run
+let x = 1;
+
+function func() {
+*!*
+ console.log(x); // ReferenceError: Cannot access 'x' before initialization
+*/!*
+ let x = 2;
+}
+
+func();
+```
+
+In this example we can observe the peculiar difference between a "non-existing" and "uninitialized" variable.
+
+As you may have read in the article [](info:closure), a variable starts in the "uninitialized" state from the moment when the execution enters a code block (or a function). And it stays uninitalized until the corresponding `let` statement.
+
+In other words, a variable technically exists, but can't be used before `let`.
+
+The code above demonstrates it.
+
+```js
+function func() {
+*!*
+ // the local variable x is known to the engine from the beginning of the function,
+ // but "unitialized" (unusable) until let ("dead zone")
+ // hence the error
+*/!*
+
+ console.log(x); // ReferenceError: Cannot access 'x' before initialization
+
+ let x = 2;
+}
+```
+
+This zone of temporary unusability of a variable (from the beginning of the code block till `let`) is sometimes called the "dead zone".
diff --git a/1-js/06-advanced-functions/03-closure/7-let-scope/task.md b/1-js/06-advanced-functions/03-closure/7-let-scope/task.md
new file mode 100644
index 0000000000..fb7445e66a
--- /dev/null
+++ b/1-js/06-advanced-functions/03-closure/7-let-scope/task.md
@@ -0,0 +1,21 @@
+importance: 4
+
+---
+
+# Is variable visible?
+
+What will be the result of this code?
+
+```js
+let x = 1;
+
+function func() {
+ console.log(x); // ?
+
+ let x = 2;
+}
+
+func();
+```
+
+P.S. There's a pitfall in this task. The solution is not obvious.
diff --git a/1-js/06-advanced-functions/03-closure/7-sort-by-field/solution.md b/1-js/06-advanced-functions/03-closure/7-sort-by-field/solution.md
deleted file mode 100644
index bd57085eaf..0000000000
--- a/1-js/06-advanced-functions/03-closure/7-sort-by-field/solution.md
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-```js run
-let users = [
- { name: "John", age: 20, surname: "Johnson" },
- { name: "Pete", age: 18, surname: "Peterson" },
- { name: "Ann", age: 19, surname: "Hathaway" }
-];
-
-*!*
-function byField(field) {
- return (a, b) => a[field] > b[field] ? 1 : -1;
-}
-*/!*
-
-users.sort(byField('name'));
-users.forEach(user => alert(user.name)); // Ann, John, Pete
-
-users.sort(byField('age'));
-users.forEach(user => alert(user.name)); // Pete, Ann, John
-```
-
diff --git a/1-js/06-advanced-functions/03-closure/6-filter-through-function/_js.view/solution.js b/1-js/06-advanced-functions/03-closure/8-filter-through-function/_js.view/solution.js
similarity index 100%
rename from 1-js/06-advanced-functions/03-closure/6-filter-through-function/_js.view/solution.js
rename to 1-js/06-advanced-functions/03-closure/8-filter-through-function/_js.view/solution.js
diff --git a/1-js/06-advanced-functions/03-closure/6-filter-through-function/_js.view/source.js b/1-js/06-advanced-functions/03-closure/8-filter-through-function/_js.view/source.js
similarity index 100%
rename from 1-js/06-advanced-functions/03-closure/6-filter-through-function/_js.view/source.js
rename to 1-js/06-advanced-functions/03-closure/8-filter-through-function/_js.view/source.js
diff --git a/1-js/06-advanced-functions/03-closure/6-filter-through-function/_js.view/test.js b/1-js/06-advanced-functions/03-closure/8-filter-through-function/_js.view/test.js
similarity index 100%
rename from 1-js/06-advanced-functions/03-closure/6-filter-through-function/_js.view/test.js
rename to 1-js/06-advanced-functions/03-closure/8-filter-through-function/_js.view/test.js
diff --git a/1-js/06-advanced-functions/03-closure/6-filter-through-function/solution.md b/1-js/06-advanced-functions/03-closure/8-filter-through-function/solution.md
similarity index 100%
rename from 1-js/06-advanced-functions/03-closure/6-filter-through-function/solution.md
rename to 1-js/06-advanced-functions/03-closure/8-filter-through-function/solution.md
diff --git a/1-js/06-advanced-functions/03-closure/6-filter-through-function/task.md b/1-js/06-advanced-functions/03-closure/8-filter-through-function/task.md
similarity index 100%
rename from 1-js/06-advanced-functions/03-closure/6-filter-through-function/task.md
rename to 1-js/06-advanced-functions/03-closure/8-filter-through-function/task.md
diff --git a/1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/solution.js b/1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/solution.js
new file mode 100644
index 0000000000..8a71c869d9
--- /dev/null
+++ b/1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/solution.js
@@ -0,0 +1,3 @@
+function byField(fieldName){
+ return (a, b) => a[fieldName] > b[fieldName] ? 1 : -1;
+}
diff --git a/1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/source.js b/1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/source.js
new file mode 100644
index 0000000000..23b4338340
--- /dev/null
+++ b/1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/source.js
@@ -0,0 +1,5 @@
+function byField(fieldName){
+
+ // Your code goes here.
+
+}
diff --git a/1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/test.js b/1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/test.js
new file mode 100644
index 0000000000..e3c335e03a
--- /dev/null
+++ b/1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/test.js
@@ -0,0 +1,39 @@
+describe("byField", function(){
+
+ let users = [
+ { name: "John", age: 20, surname: "Johnson" },
+ { name: "Pete", age: 18, surname: "Peterson" },
+ { name: "Ann", age: 19, surname: "Hathaway" },
+ ];
+
+ it("sorts users by name", function(){
+ let nameSortedKey = [
+ { name: "Ann", age: 19, surname: "Hathaway" },
+ { name: "John", age: 20, surname: "Johnson"},
+ { name: "Pete", age: 18, surname: "Peterson" },
+ ];
+ let nameSortedAnswer = users.sort(byField("name"));
+ assert.deepEqual(nameSortedKey, nameSortedAnswer);
+ });
+
+ it("sorts users by age", function(){
+ let ageSortedKey = [
+ { name: "Pete", age: 18, surname: "Peterson" },
+ { name: "Ann", age: 19, surname: "Hathaway" },
+ { name: "John", age: 20, surname: "Johnson"},
+ ];
+ let ageSortedAnswer = users.sort(byField("age"));
+ assert.deepEqual(ageSortedKey, ageSortedKey);
+ });
+
+ it("sorts users by surname", function(){
+ let surnameSortedKey = [
+ { name: "Ann", age: 19, surname: "Hathaway" },
+ { name: "John", age: 20, surname: "Johnson"},
+ { name: "Pete", age: 18, surname: "Peterson" },
+ ];
+ let surnameSortedAnswer = users.sort(byField("surname"));
+ assert.deepEqual(surnameSortedAnswer, surnameSortedKey);
+ });
+
+});
diff --git a/1-js/06-advanced-functions/03-closure/9-sort-by-field/solution.md b/1-js/06-advanced-functions/03-closure/9-sort-by-field/solution.md
new file mode 100644
index 0000000000..8b13789179
--- /dev/null
+++ b/1-js/06-advanced-functions/03-closure/9-sort-by-field/solution.md
@@ -0,0 +1 @@
+
diff --git a/1-js/06-advanced-functions/03-closure/7-sort-by-field/task.md b/1-js/06-advanced-functions/03-closure/9-sort-by-field/task.md
similarity index 100%
rename from 1-js/06-advanced-functions/03-closure/7-sort-by-field/task.md
rename to 1-js/06-advanced-functions/03-closure/9-sort-by-field/task.md
diff --git a/1-js/06-advanced-functions/03-closure/article.md b/1-js/06-advanced-functions/03-closure/article.md
index 15e61516bc..78689859da 100644
--- a/1-js/06-advanced-functions/03-closure/article.md
+++ b/1-js/06-advanced-functions/03-closure/article.md
@@ -1,4 +1,5 @@
+<<<<<<< HEAD
# Замыкание
JavaScript - язык с сильным функционально-ориентированным уклоном. Он даёт нам много свободы. Функция может быть динамически создана, скопирована в другую переменную или передана как аргумент другой функции и позже вызвана из совершенно другого места.
@@ -166,29 +167,105 @@ JavaScript - язык с сильным функционально-ориент
Старые значения переменных нигде не сохраняются. Когда функция хочет получить доступ к переменной, она берёт её текущее значение из своего или внешнего лексического окружения.
Так что, ответ на первый вопрос: `Pete`:
+=======
+# Variable scope, closure
+
+JavaScript is a very function-oriented language. It gives us a lot of freedom. A function can be created at any moment, passed as an argument to another function, and then called from a totally different place of code later.
+
+We already know that a function can access variables outside of it ("outer" variables).
+
+But what happens if outer variables change since a function is created? Will the function get newer values or the old ones?
+
+And what if a function is passed along as a parameter and called from another place of code, will it get access to outer variables at the new place?
+
+Let's expand our knowledge to understand these scenarios and more complex ones.
+
+```smart header="We'll talk about `let/const` variables here"
+In JavaScript, there are 3 ways to declare a variable: `let`, `const` (the modern ones), and `var` (the remnant of the past).
+
+- In this article we'll use `let` variables in examples.
+- Variables, declared with `const`, behave the same, so this article is about `const` too.
+- The old `var` has some notable differences, they will be covered in the article .
+```
+
+## Code blocks
+
+If a variable is declared inside a code block `{...}`, it's only visible inside that block.
+
+For example:
+
+```js run
+{
+ // do some job with local variables that should not be seen outside
+
+ let message = "Hello"; // only visible in this block
+
+ alert(message); // Hello
+}
+
+alert(message); // Error: message is not defined
+```
+
+We can use this to isolate a piece of code that does its own task, with variables that only belong to it:
```js run
-let name = "John";
+{
+ // show message
+ let message = "Hello";
+ alert(message);
+}
-function sayHi() {
- alert("Hi, " + name);
+{
+ // show another message
+ let message = "Goodbye";
+ alert(message);
}
+```
-name = "Pete"; // (*)
+````smart header="There'd be an error without blocks"
+Please note, without separate blocks there would be an error, if we use `let` with the existing variable name:
+```js run
+// show message
+let message = "Hello";
+alert(message);
+
+// show another message
*!*
-sayHi(); // Pete
+let message = "Goodbye"; // Error: variable already declared
*/!*
+alert(message);
```
+````
+
+For `if`, `for`, `while` and so on, variables declared in `{...}` are also only visible inside:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
+```js run
+if (true) {
+ let phrase = "Hello!";
+ alert(phrase); // Hello!
+}
+
+alert(phrase); // Error, no such variable!
+```
+
+Here, after `if` finishes, the `alert` below won't see the `phrase`, hence the error.
+
+<<<<<<< HEAD
Порядок выполнения кода, приведённого выше:
1. В глобальном лексическом окружении есть `name: "John"`.
2. На строке `(*)` глобальная переменная изменяется, теперь `name: "Pete"`.
3. Момент, когда выполняется функция `sayHi()` и берёт переменную `name` извне. Теперь из глобального лексического окружения, где переменная уже равна `"Pete"`.
+=======
+That's great, as it allows us to create block-local variables, specific to an `if` branch.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
+The similar thing holds true for `for` and `while` loops:
+<<<<<<< HEAD
```smart header="Один вызов -- одно лексическое окружение"
Пожалуйста, обратите внимание, что новое лексическое окружение функции создаётся каждый раз, когда функция выполняется.
@@ -197,8 +274,18 @@ sayHi(); // Pete
```smart header="Лексическое окружение -- это специальный внутренний объект"
"Лексическое окружение" -- это специальный внутренний объект. Мы не можем получить его в нашем коде и изменять напрямую. Сам движок JavaScript может оптимизировать его, уничтожать неиспользуемые переменные для освобождения памяти и выполнять другие внутренние уловки, но видимое поведение объекта должно оставаться таким, как было описано.
+=======
+```js run
+for (let i = 0; i < 3; i++) {
+ // the variable i is only visible inside this for
+ alert(i); // 0, then 1, then 2
+}
+
+alert(i); // Error, no such variable
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```
+Visually, `let i` is outside of `{...}`. But the `for` construct is special here: the variable, declared inside it, is considered a part of the block.
## Вложенные функции
@@ -224,6 +311,7 @@ function sayHiBye(firstName, lastName) {
Здесь *вложенная* функция `getFullName()` создана для удобства. Она может получить доступ к внешним переменным и, значит, вывести полное имя. В JavaScript вложенные функции используются очень часто.
+<<<<<<< HEAD
Что ещё интереснее, вложенная функция может быть возвращена: либо в качестве свойства нового объекта (если внешняя функция создаёт объект с методами), либо сама по себе. И затем может быть использована в любом месте. Не важно где, она всё так же будет иметь доступ к тем же внешним переменным.
Например, здесь, вложенная функция присваивается новому объекту в [конструкторе](info:constructor-new):
@@ -243,13 +331,22 @@ user.sayHi(); // у кода метода "sayHi" есть доступ к вн
```
А здесь мы просто создаём и возвращаем функцию "счётчик":
+=======
+What's much more interesting, a nested function can be returned: either as a property of a new object or as a result by itself. It can then be used somewhere else. No matter where, it still has access to the same outer variables.
+
+Below, `makeCounter` creates the "counter" function that returns the next number on each invocation:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js run
function makeCounter() {
let count = 0;
return function() {
+<<<<<<< HEAD
return count++; // есть доступ к внешней переменной "count"
+=======
+ return count++;
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
};
}
@@ -260,14 +357,19 @@ alert( counter() ); // 1
alert( counter() ); // 2
```
+<<<<<<< HEAD
Давайте продолжим с примером `makeCounter`. Он создаёт функцию "counter", которая возвращает следующее число при каждом вызове. Несмотря на простоту, немного модифицированные варианты этого кода применяются на практике, например, в [генераторе псевдослучайных чисел](https://ru.wikipedia.org/wiki/Генератор_псевдослучайных_чисел) и во многих других случаях.
Как же это работает изнутри?
Когда внутренняя функция начинает выполняться, начинается поиск переменной `count++` изнутри-наружу. Для примера выше порядок будет такой:
+=======
+Despite being simple, slightly modified variants of that code have practical uses, for instance, as a [random number generator](https://en.wikipedia.org/wiki/Pseudorandom_number_generator) to generate random values for automated tests.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
-
+How does this work? If we create multiple counters, will they be independent? What's going on with the variables here?
+<<<<<<< HEAD
1. Локальные переменные вложенной функции...
2. Переменные внешней функции...
3. И так далее, пока не будут достигнуты глобальные переменные.
@@ -302,14 +404,24 @@ function makeCounter() {
let counter1 = makeCounter();
let counter2 = makeCounter();
+=======
+Undestanding such things is great for the overall knowledge of JavaScript and beneficial for more complex scenarios. So let's go a bit in-depth.
-alert( counter1() ); // 0
-alert( counter1() ); // 1
+## Lexical Environment
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
+```warn header="Here be dragons!"
+The in-depth technical explanation lies ahead.
+
+<<<<<<< HEAD
alert( counter2() ); // 0 (независимо)
+=======
+As far as I'd like to avoid low-level language details, any understanding without them would be lacking and incomplete, so get ready.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```
Надеюсь, ситуация с внешними переменными теперь ясна. Для большинства ситуаций такого понимания вполне достаточно, но в спецификации есть ряд деталей, которые мы, для простоты, опустили. Далее мы разберём происходящее ещё более подробно.
+<<<<<<< HEAD
## Окружение в деталях
Вот что происходит в примере с `makeCounter` шаг за шагом. Пройдите их, чтобы убедиться, что вы разобрались с каждой деталью.
@@ -347,21 +459,42 @@ alert( counter2() ); // 0 (независимо)
Не имеет значения, какой способ объявления функции используется: Function Declaration или Function Expression. Все функции получают свойство `[[Environment]]`, которое ссылается на лексическое окружение, в котором они были созданы. То же самое происходит и с нашей новой маленькой функцией.
Для нашей новой вложенной функции значением `[[Environment]]` будет текущее лексическое окружение `makeCounter()` (где она была создана):
+=======
+For clarity, the explanation is split into multiple steps.
+
+### Step 1. Variables
- 
+In JavaScript, every running function, code block `{...}`, and the script as a whole have an internal (hidden) associated object known as the *Lexical Environment*.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
+The Lexical Environment object consists of two parts:
+
+<<<<<<< HEAD
Пожалуйста, обратите внимание, что на этом шаге внутренняя функция была создана, но ещё не вызвана. Код внутри `function() { return count++ }` не выполняется.
4. Выполнение продолжается, вызов `makeCounter()` завершается, и результат (небольшая вложенная функция) присваивается глобальной переменной `counter`:
+=======
+1. *Environment Record* -- an object that stores all local variables as its properties (and some other information like the value of `this`).
+2. A reference to the *outer lexical environment*, the one associated with the outer code.
+
+**A "variable" is just a property of the special internal object, `Environment Record`. "To get or change a variable" means "to get or change a property of that object".**
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
- 
+In this simple code without functions, there is only one Lexical Environment:
+<<<<<<< HEAD
В этой функции есть только одна строчка: `return count++`, которая будет выполнена, когда мы вызовем функцию.
6. При вызове `counter()` для этого вызова создаётся новое лексическое окружение. Оно пустое, так как в самом `counter` локальных переменных нет. Но `[[Environment]]` `counter` используется, как ссылка на внешнее лексическое окружение `outer`, которое даёт доступ к переменным предшествующего вызова `makeCounter`, где `counter` был создан.
+=======
+
+
+This is the so-called *global* Lexical Environment, associated with the whole script.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
- 
+On the picture above, the rectangle means Environment Record (variable store) and the arrow means the outer reference. The global Lexical Environment has no outer reference, that's why the arrow points to `null`.
+<<<<<<< HEAD
Теперь, когда вызов ищет переменную `count`, он сначала ищет в собственном лексическом окружении (пустое), а затем в лексическом окружении предшествующего вызова `makeCounter()`, где и находит её.
Пожалуйста, обратите внимание, как здесь работает управление памятью. Хотя `makeCounter()` закончил выполнение некоторое время назад, его лексическое окружение остаётся в памяти, потому что есть вложенная функция с `[[Environment]]`, который ссылается на него.
@@ -369,17 +502,42 @@ alert( counter2() ); // 0 (независимо)
В большинстве случаев, объект лексического окружения существует до того момента, пока есть функция, которая может его использовать. И только тогда, когда таких не остаётся, окружение уничтожается.
6. Вызов `counter()` не только возвращает значение `count`, но также увеличивает его. Обратите внимание, что модификация происходит "на месте". Значение `count` изменяется конкретно в том окружении, где оно было найдено.
+=======
+As the code starts executing and goes on, the Lexical Environment changes.
- 
+Here's a little bit longer code:
+
+
+Rectangles on the right-hand side demonstrate how the global Lexical Environment changes during the execution:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
+
+1. When the script starts, the Lexical Environment is pre-populated with all declared variables.
+ - Initially, they are in the "Uninitialized" state. That's a special internal state, it means that the engine knows about the variable, but it cannot be referenced until it has been declared with `let`. It's almost the same as if the variable didn't exist.
+2. Then `let phrase` definition appears. There's no assignment yet, so its value is `undefined`. We can use the variable from this point forward.
+3. `phrase` is assigned a value.
+4. `phrase` changes the value.
+
+<<<<<<< HEAD
7. Следующие вызовы `counter()` сделают то же самое.
Теперь ответ на второй вопрос из начала главы должен быть очевиден.
Функция `work()` в коде ниже получает `name` из того места, где была создана, через ссылку на внешнее лексическое окружение:
+=======
+Everything looks simple for now, right?
+
+- A variable is a property of a special internal object, associated with the currently executing block/function/script.
+- Working with variables is actually working with the properties of that object.
-
+```smart header="Lexical Environment is a specification object"
+"Lexical Environment" is a specification object: it only exists "theoretically" in the [language specification](https://tc39.es/ecma262/#sec-lexical-environments) to describe how things work. We can't get this object in our code and manipulate it directly.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
+JavaScript engines also may optimize it, discard variables that are unused to save memory and perform other internal tricks, as long as the visible behavior remains as described.
+```
+
+<<<<<<< HEAD
Так что, результатом будет `"Pete"`.
Но, если бы в `makeWorker()` не было `let name`, тогда бы поиск продолжился дальше и была бы взята глобальная переменная, как мы видим из приведённой выше цепочки. В таком случае, результатом было бы `"John"`.
@@ -399,21 +557,43 @@ alert( counter2() ); // 0 (независимо)
Предыдущие примеры сосредоточены на функциях. Но лексическое окружение существует для любых блоков кода `{...}`.
Лексическое окружение создаётся при выполнении блока кода и содержит локальные переменные для этого блока. Вот пара примеров.
+=======
+### Step 2. Function Declarations
+
+A function is also a value, like a variable.
+
+**The difference is that a Function Declaration is instantly fully initialized.**
+
+When a Lexical Environment is created, a Function Declaration immediately becomes a ready-to-use function (unlike `let`, that is unusable till the declaration).
+
+That's why we can use a function, declared as Function Declaration, even before the declaration itself.
+
+For example, here's the initial state of the global Lexical Environment when we add a function:
+
+
+
+Naturally, this behavior only applies to Function Declarations, not Function Expressions where we assign a function to a variable, such as `let say = function(name)...`.
+
+### Step 3. Inner and outer Lexical Environment
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
-### If
+When a function runs, at the beginning of the call, a new Lexical Environment is created automatically to store local variables and parameters of the call.
+<<<<<<< HEAD
В следующем примере переменная `user` существует только в блоке `if`:
+=======
+For instance, for `say("John")`, it looks like this (the execution is at the line, labelled with an arrow):
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
@@ -424,9 +604,16 @@ alert( counter2() ); // 0 (независимо)
У него есть ссылка на внешнее окружение, так что `phrase` может быть найдена. Но все переменные и Function Expression, объявленные внутри `if`, остаются в его лексическом окружении и не видны снаружи.
Например, после завершения `if` следующий `alert` не увидит `user`, что вызовет ошибку.
+=======
+ say("John"); // Hello, John
+ ```-->
-### For, while
+
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
+During the function call we have two Lexical Environments: the inner one (for the function call) and the outer one (global):
+
+<<<<<<< HEAD
Для цикла у каждой итерации своё отдельное лексическое окружение. Если переменная объявлена в `for(let ...)`, то она также в нём:
```js run
@@ -457,10 +644,39 @@ alert(i); // Ошибка, нет такой переменной
// сделать какую-нибудь работу с локальными переменными, которые не должны быть видны снаружи
let message = "Hello";
+=======
+- The inner Lexical Environment corresponds to the current execution of `say`. It has a single property: `name`, the function argument. We called `say("John")`, so the value of the `name` is `"John"`.
+- The outer Lexical Environment is the global Lexical Environment. It has the `phrase` variable and the function itself.
- alert(message); // Hello
+The inner Lexical Environment has a reference to the `outer` one.
+
+**When the code wants to access a variable -- the inner Lexical Environment is searched first, then the outer one, then the more outer one and so on until the global one.**
+
+If a variable is not found anywhere, that's an error in strict mode (without `use strict`, an assignment to a non-existing variable creates a new global variable, for compatibility with old code).
+
+In this example the search proceeds as follows:
+
+- For the `name` variable, the `alert` inside `say` finds it immediately in the inner Lexical Environment.
+- When it wants to access `phrase`, then there is no `phrase` locally, so it follows the reference to the outer Lexical Environment and finds it there.
+
+
+
+
+### Step 4. Returning a function
+
+Let's return to the `makeCounter` example.
+
+```js
+function makeCounter() {
+ let count = 0;
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
+
+ return function() {
+ return count++;
+ };
}
+<<<<<<< HEAD
alert(message); // Ошибка: переменная message не определена
```
@@ -480,12 +696,18 @@ IIFE выглядит так:
(function() {
let message = "Hello";
+=======
+let counter = makeCounter();
+```
- alert(message); // Hello
+At the beginning of each `makeCounter()` call, a new Lexical Environment object is created, to store variables for this `makeCounter` run.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
-})();
-```
+So we have two nested Lexical Environments, just like in the example above:
+
+
+<<<<<<< HEAD
Здесь создаётся и немедленно вызывается Function Expression. Так что код выполняется сразу же и у него есть свои локальные переменные.
Function Expression обёрнуто в скобки `(function {...})`, потому что, когда JavaScript встречает `"function"` в основном потоке кода, он воспринимает это как начало Function Declaration. Но у Function Declaration должно быть имя, так что такой код вызовет ошибку:
@@ -493,14 +715,21 @@ Function Expression обёрнуто в скобки `(function {...})`, пот
```js run
// Попробуйте объявить и сразу же вызвать функцию
function() { // <-- Error: Unexpected token (
+=======
+What's different is that, during the execution of `makeCounter()`, a tiny nested function is created of only one line: `return count++`. We don't run it yet, only create.
- let message = "Hello";
+All functions remember the Lexical Environment in which they were made. Technically, there's no magic here: all functions have the hidden property named `[[Environment]]`, that keeps the reference to the Lexical Environment where the function was created:
- alert(message); // Hello
+
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
-}();
-```
+So, `counter.[[Environment]]` has the reference to `{count: 0}` Lexical Environment. That's how the function remembers where it was created, no matter where it's called. The `[[Environment]]` reference is set once and forever at function creation time.
+
+Later, when `counter()` is called, a new Lexical Environment is created for the call, and its outer Lexical Environment reference is taken from `counter.[[Environment]]`:
+
+
+<<<<<<< HEAD
Даже если мы скажем: "хорошо, давайте добавим имя", -- это не сработает, потому что JavaScript не позволяет вызывать Function Declaration немедленно.
```js run
@@ -538,32 +767,59 @@ function go() {
## Сборка мусора
Обычно лексическое окружение очищается и удаляется после того, как функция выполнилась. Например:
+=======
+Now when the code inside `counter()` looks for `count` variable, it first searches its own Lexical Environment (empty, as there are no local variables there), then the Lexical Environment of the outer `makeCounter()` call, where it finds and changes it.
-```js
-function f() {
- let value1 = 123;
- let value2 = 456;
-}
+**A variable is updated in the Lexical Environment where it lives.**
-f();
+Here's the state after the execution:
+
+
+
+If we call `counter()` multiple times, the `count` variable will be increased to `2`, `3` and so on, at the same place.
+
+```smart header="Closure"
+There is a general programming term "closure", that developers generally should know.
+
+A [closure](https://en.wikipedia.org/wiki/Closure_(computer_programming)) is a function that remembers its outer variables and can access them. In some languages, that's not possible, or a function should be written in a special way to make it happen. But as explained above, in JavaScript, all functions are naturally closures (there is only one exception, to be covered in ).
+
+That is: they automatically remember where they were created using a hidden `[[Environment]]` property, and then their code can access outer variables.
+
+When on an interview, a frontend developer gets a question about "what's a closure?", a valid answer would be a definition of the closure and an explanation that all functions in JavaScript are closures, and maybe a few more words about technical details: the `[[Environment]]` property and how Lexical Environments work.
```
+## Garbage collection
+
+Usually, a Lexical Environment is removed from memory with all the variables after the function call finishes. That's because there are no references to it. As any JavaScript object, it's only kept in memory while it's reachable.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
+
+...But if there's a nested function that is still reachable after the end of a function, then it has `[[Environment]]` property that references the lexical environment.
+
+<<<<<<< HEAD
Здесь два значения, которые технически являются свойствами лексического окружения. Но после того, как `f()` завершится, это лексическое окружение станет недоступно, поэтому оно удалится из памяти.
...Но, если есть вложенная функция, которая всё ещё доступна после выполнения `f`, то у неё есть свойство `[[Environment]]`, которое ссылается на внешнее лексическое окружение, тем самым оставляя его достижимым, "живым":
+=======
+In that case the Lexical Environment is still reachable even after the completion of the function, so it stays alive.
+
+For example:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js
function f() {
let value = 123;
- function g() { alert(value); }
-
-*!*
- return g;
-*/!*
+ return function() {
+ alert(value);
+ }
}
+<<<<<<< HEAD
let g = f(); // g доступно и продолжает держать внешнее лексическое окружение в памяти
+=======
+let g = f(); // g.[[Environment]] stores a reference to the Lexical Environment
+// of the corresponding f() call
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```
Обратите внимание, если `f()` вызывается несколько раз и возвращаемые функции сохраняются, тогда все соответствующие объекты лексического окружения продолжат держаться в памяти. Вот три такие функции в коде ниже:
@@ -582,19 +838,27 @@ let arr = [f(), f(), f()];
Объект лексического окружения умирает, когда становится недоступным (как и любой другой объект). Другими словами, он существует только до того момента, пока есть хотя бы одна вложенная функция, которая ссылается на него.
+<<<<<<< HEAD
В следующем коде, после того как `g` станет недоступным, лексическое окружение функции (и, соответственно, `value`) будет удалено из памяти;
+=======
+In the code below, after the nested function is removed, its enclosing Lexical Environment (and hence the `value`) is cleaned from memory:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js
function f() {
let value = 123;
- function g() { alert(value); }
-
- return g;
+ return function() {
+ alert(value);
+ }
}
+<<<<<<< HEAD
let g = f(); // пока g существует,
// соответствующее лексическое окружение существует
+=======
+let g = f(); // while g function exists, the value stays in memory
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
g = null; // ...а теперь память очищается
```
@@ -647,9 +911,15 @@ let g = f();
g();
```
+<<<<<<< HEAD
```warn header="До встречи!"
Эту особенность V8 полезно знать. Если вы занимаетесь отладкой в Chrome/Opera, рано или поздно вы с ней встретитесь.
Это не баг в отладчике, а скорее особенность V8. Возможно со временем это изменится.
Вы всегда можете проверить это, запустив пример на этой странице.
```
+=======
+This feature of V8 is good to know. If you are debugging with Chrome/Opera, sooner or later you will meet it.
+
+That is not a bug in the debugger, but rather a special feature of V8. Perhaps it will be changed sometime. You always can check for it by running the examples on this page.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
diff --git a/1-js/06-advanced-functions/03-closure/closure-function-declaration.svg b/1-js/06-advanced-functions/03-closure/closure-function-declaration.svg
new file mode 100644
index 0000000000..97f76e5691
--- /dev/null
+++ b/1-js/06-advanced-functions/03-closure/closure-function-declaration.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/06-advanced-functions/03-closure/closure-makecounter-environment.svg b/1-js/06-advanced-functions/03-closure/closure-makecounter-environment.svg
new file mode 100644
index 0000000000..b9060bc8a2
--- /dev/null
+++ b/1-js/06-advanced-functions/03-closure/closure-makecounter-environment.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/06-advanced-functions/03-closure/closure-makecounter-nested-call-2.svg b/1-js/06-advanced-functions/03-closure/closure-makecounter-nested-call-2.svg
new file mode 100644
index 0000000000..3e4206ca6d
--- /dev/null
+++ b/1-js/06-advanced-functions/03-closure/closure-makecounter-nested-call-2.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/06-advanced-functions/03-closure/closure-makecounter-nested-call.svg b/1-js/06-advanced-functions/03-closure/closure-makecounter-nested-call.svg
new file mode 100644
index 0000000000..e1bb8cc8f9
--- /dev/null
+++ b/1-js/06-advanced-functions/03-closure/closure-makecounter-nested-call.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/06-advanced-functions/03-closure/closure-makecounter.svg b/1-js/06-advanced-functions/03-closure/closure-makecounter.svg
new file mode 100644
index 0000000000..2a1c4a7296
--- /dev/null
+++ b/1-js/06-advanced-functions/03-closure/closure-makecounter.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/06-advanced-functions/03-closure/closure-variable-phrase.svg b/1-js/06-advanced-functions/03-closure/closure-variable-phrase.svg
new file mode 100644
index 0000000000..741c054487
--- /dev/null
+++ b/1-js/06-advanced-functions/03-closure/closure-variable-phrase.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/06-advanced-functions/03-closure/variable-scope-lookup.svg b/1-js/06-advanced-functions/03-closure/variable-scope-lookup.svg
new file mode 100644
index 0000000000..674437196a
--- /dev/null
+++ b/1-js/06-advanced-functions/03-closure/variable-scope-lookup.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/06-advanced-functions/04-var/article.md b/1-js/06-advanced-functions/04-var/article.md
index 2c914de25e..fe723ff40f 100644
--- a/1-js/06-advanced-functions/04-var/article.md
+++ b/1-js/06-advanced-functions/04-var/article.md
@@ -1,12 +1,23 @@
# Устаревшее ключевое слово "var"
+<<<<<<< HEAD
В самой первой главе про [переменные](info:variables) мы ознакомились с тремя способами объявления переменных:
+=======
+```smart header="This article is for understanding old scripts"
+The information in this article is useful for understanding old scripts.
+
+That's not how we write a new code.
+```
+
+In the very first chapter about [variables](info:variables), we mentioned three ways of variable declaration:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
1. `let`
2. `const`
3. `var`
+<<<<<<< HEAD
`let` и `const` ведут себя одинаково по отношению к лексическому окружению, области видимости.
Но `var` - это совершенно другой зверь, берущий своё начало с давних времён. Обычно `var` не используется в современных скриптах, но всё ещё может скрываться в старых.
@@ -21,13 +32,27 @@ function sayHi() {
alert(phrase); // Привет
}
+=======
+The `var` declaration is similar to `let`. Most of the time we can replace `let` by `var` or vice-versa and expect things to work:
-sayHi();
+```js run
+var message = "Hi";
+alert(message); // Hi
+```
+
+But internally `var` is a very different beast, that originates from very old times. It's generally not used in modern scripts, but still lurks in the old ones.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
+If you don't plan on meeting such scripts you may even skip this chapter or postpone it.
+
+<<<<<<< HEAD
alert(phrase); // Ошибка: phrase не определена
```
...Однако, отличия всё же есть.
+=======
+On the other hand, it's important to understand differences when migrating old scripts from `var` to `let`, to avoid odd errors.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
## Для "var" не существует блочной области видимости
@@ -88,7 +113,31 @@ alert(phrase); // Ошибка: phrase не определена (видна в
Как мы видим, `var` выходит за пределы блоков `if`, `for` и подобных. Это происходит потому, что на заре развития JavaScript блоки кода не имели лексического окружения. Поэтому можно сказать, что `var` - это пережиток прошлого.
+<<<<<<< HEAD
## "var" обрабатываются в начале запуска функции
+=======
+## "var" tolerates redeclarations
+
+If we declare the same variable with `let` twice in the same scope, that's an error:
+
+```js run
+let user;
+let user; // SyntaxError: 'user' has already been declared
+```
+
+With `var`, we can redeclare a variable any number of times. If we use `var` with an already-declared variable, it's just ignored:
+
+```js run
+var user = "Pete";
+
+var user = "John"; // this "var" does nothing (already declared)
+// ...it doesn't trigger an error
+
+alert(user); // John
+```
+
+## "var" variables can be declared below their use
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Объявления переменных `var` обрабатываются в начале выполнения функции (или запуска скрипта, если переменная является глобальной).
@@ -147,7 +196,11 @@ sayHi();
**Объявления переменных "всплывают", но присваивания значений - нет.**
+<<<<<<< HEAD
Это проще всего продемонстрировать на примере:
+=======
+That's best demonstrated with an example:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js run
function sayHi() {
@@ -188,13 +241,89 @@ sayHi();
В обоих примерах выше вызов `alert` происходил без ошибки, потому что переменная `phrase` уже существовала. Но её значение ещё не было присвоено, поэтому мы получали `undefined`.
+<<<<<<< HEAD
## Итого
+=======
+### IIFE
+
+As in the past there was only `var`, and it has no block-level visibility, programmers invented a way to emulate it. What they did was called "immediately-invoked function expressions" (abbreviated as IIFE).
+
+That's not something we should use nowadays, but you can find them in old scripts.
+
+An IIFE looks like this:
+
+```js run
+(function() {
+
+ let message = "Hello";
+
+ alert(message); // Hello
+
+})();
+```
+
+Here a Function Expression is created and immediately called. So the code executes right away and has its own private variables.
+
+The Function Expression is wrapped with parenthesis `(function {...})`, because when JavaScript meets `"function"` in the main code flow, it understands it as the start of a Function Declaration. But a Function Declaration must have a name, so this kind of code will give an error:
+
+```js run
+// Try to declare and immediately call a function
+function() { // <-- Error: Function statements require a function name
+
+ let message = "Hello";
+
+ alert(message); // Hello
+
+}();
+```
+
+Even if we say: "okay, let's add a name", that won't work, as JavaScript does not allow Function Declarations to be called immediately:
+
+```js run
+// syntax error because of parentheses below
+function go() {
+
+}(); // <-- can't call Function Declaration immediately
+```
+
+So, the parentheses around the function is a trick to show JavaScript that the function is created in the context of another expression, and hence it's a Function Expression: it needs no name and can be called immediately.
+
+There exist other ways besides parentheses to tell JavaScript that we mean a Function Expression:
+
+```js run
+// Ways to create IIFE
+
+(function() {
+ alert("Parentheses around the function");
+}*!*)*/!*();
+
+(function() {
+ alert("Parentheses around the whole thing");
+}()*!*)*/!*;
+
+*!*!*/!*function() {
+ alert("Bitwise NOT operator starts the expression");
+}();
+
+*!*+*/!*function() {
+ alert("Unary plus starts the expression");
+}();
+```
+
+In all the above cases we declare a Function Expression and run it immediately. Let's note again: nowadays there's no reason to write such code.
+
+## Summary
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Существует 2 основных отличия `var` от `let/const`:
1. Переменные `var` не имеют блочной области видимости, они ограничены, как минимум, телом функции.
2. Объявления (инициализация) переменных `var`производится в начале исполнения функции (или скрипта для глобальных переменных).
+<<<<<<< HEAD
Есть ещё одно небольшое отличие, относящееся к глобальному объекту, мы рассмотрим его в следующей главе.
+=======
+There's one more very minor difference related to the global object, that we'll cover in the next chapter.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Эти особенности, как правило, не очень хорошо влияют на код. Блочная область видимости - это удобно. Поэтому много лет назад `let` и `const` были введены в стандарт и сейчас являются основным способом объявления переменных.
diff --git a/1-js/06-advanced-functions/05-global-object/article.md b/1-js/06-advanced-functions/05-global-object/article.md
index a5e9f2b612..bbf988aeda 100644
--- a/1-js/06-advanced-functions/05-global-object/article.md
+++ b/1-js/06-advanced-functions/05-global-object/article.md
@@ -5,7 +5,11 @@
В браузере он называется `window`, в Node.js — `global`, в другой среде исполнения может называться иначе.
+<<<<<<< HEAD
Недавно `globalThis` был добавлен в язык как стандартизированное имя для глобального объекта, которое должно поддерживаться в любом окружении. В некоторых браузерах, например Edge не на Chromium, `globalThis` ещё не поддерживается, но легко реализуется с помощью полифила.
+=======
+Recently, `globalThis` was added to the language, as a standardized name for a global object, that should be supported across all environments. It's supported in all major browsers.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Далее мы будем использовать `window`, полагая, что наша среда - браузер. Если скрипт может выполняться и в другом окружении, лучше будет `globalThis`.
@@ -82,7 +86,14 @@ if (!window.Promise) {
Это включает в себя как встроенные объекты, например, `Array`, так и характерные для окружения свойства, например, `window.innerHeight` -- высота окна браузера.
- Глобальный объект имеет универсальное имя -- `globalThis`.
+<<<<<<< HEAD
...Но чаще на него ссылаются по-старому, используя имя, характерное для данного окружения, такое как `window` (браузер) и `global` (Node.js). Так как `globalThis` появился недавно, он не поддерживается в IE и Edge (не-Chromium версия), но можно использовать полифил.
- Следует хранить значения в глобальном объекте, только если они действительно глобальны для нашего проекта. И стараться свести их количество к минимуму.
- В браузерах, если только мы не используем [модули](info:modules), глобальные функции и переменные, объявленные с помощью `var`, становятся свойствами глобального объекта.
- Для того, чтобы код был проще и в будущем его легче было поддерживать, следует обращаться к свойствам глобального объекта напрямую, как `window.x`.
+=======
+ ...But more often is referred by "old-school" environment-specific names, such as `window` (browser) and `global` (Node.js).
+- We should store values in the global object only if they're truly global for our project. And keep their number at minimum.
+- In-browser, unless we're using [modules](info:modules), global functions and variables declared with `var` become a property of the global object.
+- To make our code future-proof and easier to understand, we should access properties of the global object directly, as `window.x`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
diff --git a/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/_js.view/solution.js b/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/_js.view/solution.js
new file mode 100644
index 0000000000..c7d7d734ea
--- /dev/null
+++ b/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/_js.view/solution.js
@@ -0,0 +1,15 @@
+function sum(a) {
+
+ let currentSum = a;
+
+ function f(b) {
+ currentSum += b;
+ return f;
+ }
+
+ f.toString = function() {
+ return currentSum;
+ };
+
+ return f;
+}
diff --git a/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/_js.view/source.js b/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/_js.view/source.js
new file mode 100644
index 0000000000..f10dca5dc8
--- /dev/null
+++ b/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/_js.view/source.js
@@ -0,0 +1,12 @@
+function sum(a){
+ // Your code goes here.
+
+}
+
+/*
+sum(1)(2) == 3; // 1 + 2
+sum(1)(2)(3) == 6; // 1 + 2 + 3
+sum(5)(-1)(2) == 6
+sum(6)(-1)(-2)(-3) == 0
+sum(0)(1)(2)(3)(4)(5) == 15
+*/
diff --git a/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/_js.view/test.js b/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/_js.view/test.js
new file mode 100644
index 0000000000..ed567d3306
--- /dev/null
+++ b/1-js/06-advanced-functions/06-function-object/5-sum-many-brackets/_js.view/test.js
@@ -0,0 +1,19 @@
+describe("sum", function(){
+
+ it("sum(1)(2) == 3", function(){
+ assert.equal(3, sum(1)(2));
+ });
+
+ it("sum(5)(-1)(2) == 6", function(){
+ assert.equal(6, sum(5)(-1)(2));
+ });
+
+ it("sum(6)(-1)(-2)(-3) == 0", function(){
+ assert.equal(0, sum(6)(-1)(-2)(-3));
+ });
+
+ it("sum(0)(1)(2)(3)(4)(5) == 15", function(){
+ assert.equal(15, sum(0)(1)(2)(3)(4)(5));
+ });
+});
+
diff --git a/1-js/06-advanced-functions/06-function-object/article.md b/1-js/06-advanced-functions/06-function-object/article.md
index b7e2a6823c..c92ab8b796 100644
--- a/1-js/06-advanced-functions/06-function-object/article.md
+++ b/1-js/06-advanced-functions/06-function-object/article.md
@@ -67,8 +67,13 @@ alert(user.sayBye.name); // sayBye
В этом нет никакой магии. Бывает, что корректное имя определить невозможно. В таких случаях свойство name имеет пустое значение. Например:
+<<<<<<< HEAD
```js
// функция объявлена внутри массива
+=======
+```js run
+// function created inside array
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
let arr = [function() {}];
alert( arr[0].name ); // <пустая строка>
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 5677fc09a6..8728ae30e0 100644
--- a/1-js/06-advanced-functions/08-settimeout-setinterval/article.md
+++ b/1-js/06-advanced-functions/08-settimeout-setinterval/article.md
@@ -61,7 +61,11 @@ setTimeout(sayHi, 1000, "Привет", "Джон"); // Привет, Джон
setTimeout("alert('Привет')", 1000);
```
+<<<<<<< HEAD
Но использование строк не рекомендуется. Вместо этого используйте функции. Например, так:
+=======
+But using strings is not recommended, use arrow functions instead of them, like this:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js run no-beautify
setTimeout(() => alert('Привет'), 1000);
@@ -183,7 +187,7 @@ let timerId = setTimeout(function request() {
```js
let i = 1;
setInterval(function() {
- func(i);
+ func(i++);
}, 100);
```
@@ -192,12 +196,16 @@ setInterval(function() {
```js
let i = 1;
setTimeout(function run() {
- func(i);
+ func(i++);
setTimeout(run, 100);
}, 100);
```
+<<<<<<< HEAD
Для `setInterval` внутренний планировщик будет выполнять `func(i)` каждые 100 мс:
+=======
+For `setInterval` the internal scheduler will run `func(i++)` every 100ms:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a

@@ -286,11 +294,19 @@ setTimeout(function run() {
## Итого
+<<<<<<< HEAD
- Методы `setInterval(func, delay, ...args)` и `setTimeout(func, delay, ...args)` позволяют выполнять `func` регулярно или только один раз после задержки `delay`, заданной в мс.
- Для отмены выполнения необходимо вызвать `clearInterval/clearTimeout` со значением, которое возвращают методы `setInterval/setTimeout`.
- Вложенный вызов `setTimeout` является более гибкой альтернативой `setInterval`. Также он позволяет более точно задать интервал между выполнениями.
- Планирование с нулевой задержкой `setTimeout(func,0)` или, что то же самое, `setTimeout(func)` используется для вызовов, которые должны быть исполнены как можно скорее, после завершения исполнения текущего кода.
- Браузер ограничивает 4-мя мс минимальную задержку между пятью и более вложенными вызовами `setTimeout`, а также для `setInterval`, начиная с 5-го вызова.
+=======
+- Methods `setTimeout(func, delay, ...args)` and `setInterval(func, delay, ...args)` allow us to run the `func` once/regularly after `delay` milliseconds.
+- To cancel the execution, we should call `clearTimeout/clearInterval` with the value returned by `setTimeout/setInterval`.
+- Nested `setTimeout` calls are a more flexible alternative to `setInterval`, allowing us to set the time *between* executions more precisely.
+- Zero delay scheduling with `setTimeout(func, 0)` (the same as `setTimeout(func)`) is used to schedule the call "as soon as possible, but after the current script is complete".
+- The browser limits the minimal delay for five or more nested call of `setTimeout` or for `setInterval` (after 5th call) to 4ms. That's for historical reasons.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Обратим внимание, что все методы планирования *не гарантируют* точную задержку.
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/solution.js b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/solution.js
index 065a77d1f9..661dd0cf41 100644
--- a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/solution.js
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/solution.js
@@ -1,15 +1,7 @@
-function debounce(f, ms) {
-
- let isCooldown = false;
-
+function debounce(func, ms) {
+ let timeout;
return function() {
- if (isCooldown) return;
-
- f.apply(this, arguments);
-
- isCooldown = true;
-
- setTimeout(() => isCooldown = false, ms);
+ clearTimeout(timeout);
+ timeout = setTimeout(() => func.apply(this, arguments), ms);
};
-
-}
\ No newline at end of file
+}
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/test.js b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/test.js
index 774bc9a6fa..1e5837e3c0 100644
--- a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/test.js
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/test.js
@@ -1,41 +1,70 @@
-describe("debounce", function() {
- before(function() {
+describe('debounce', function () {
+ before(function () {
this.clock = sinon.useFakeTimers();
});
- after(function() {
+ after(function () {
this.clock.restore();
});
+<<<<<<< HEAD
it("вызывает функцию один раз в 'ms' мс", function() {
let log = '';
+=======
+ it('for one call - runs it after given ms', function () {
+ const f = sinon.spy();
+ const debounced = debounce(f, 1000);
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
- function f(a) {
- log += a;
- }
+ debounced('test');
+ assert(f.notCalled, 'not called immediately');
+ this.clock.tick(1000);
+ assert(f.calledOnceWith('test'), 'called after 1000ms');
+ });
- f = debounce(f, 1000);
+ it('for 3 calls - runs the last one after given ms', function () {
+ const f = sinon.spy();
+ const debounced = debounce(f, 1000);
+<<<<<<< HEAD
f(1); // вызвана
f(2); // проигнорирована
setTimeout(() => f(3), 100); // проигнорирована (слишком рано)
setTimeout(() => f(4), 1100); // вызвана (1000 мс истекли)
setTimeout(() => f(5), 1500); // проигнорирована (менее 1000 мс с последнего вызова)
+=======
+ debounced('a');
+ setTimeout(() => debounced('b'), 200); // ignored (too early)
+ setTimeout(() => debounced('c'), 500); // runs (1000 ms passed)
+ this.clock.tick(1000);
- this.clock.tick(5000);
- assert.equal(log, "14");
+ assert(f.notCalled, 'not called after 1000ms');
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
+
+ this.clock.tick(500);
+
+ assert(f.calledOnceWith('c'), 'called after 1500ms');
});
+<<<<<<< HEAD
it("сохраняет контекст вызова", function() {
+=======
+ it('keeps the context of the call', function () {
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
let obj = {
f() {
assert.equal(this, obj);
- }
+ },
};
obj.f = debounce(obj.f, 1000);
- obj.f("test");
+ obj.f('test');
+ this.clock.tick(5000);
});
+<<<<<<< HEAD
+=======
+
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
});
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/debounce.svg b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/debounce.svg
new file mode 100644
index 0000000000..5896a5fa42
--- /dev/null
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/debounce.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/debounce.view/index.html b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/debounce.view/index.html
new file mode 100644
index 0000000000..e3b4d5842f
--- /dev/null
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/debounce.view/index.html
@@ -0,0 +1,24 @@
+
+
+
+Function handler is called on this input:
+
+
+
+
+
+Debounced function debounce(handler, 1000) is called on this input:
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/solution.md b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/solution.md
index 82c2ecb5fe..e870188cb0 100644
--- a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/solution.md
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/solution.md
@@ -1,19 +1,12 @@
```js demo
-function debounce(f, ms) {
-
- let isCooldown = false;
-
+function debounce(func, ms) {
+ let timeout;
return function() {
- if (isCooldown) return;
-
- f.apply(this, arguments);
-
- isCooldown = true;
-
- setTimeout(() => isCooldown = false, ms);
+ clearTimeout(timeout);
+ timeout = setTimeout(() => func.apply(this, arguments), ms);
};
-
}
+<<<<<<< HEAD
```
Вызов `debounce` возвращает обёртку. Возможны два состояния:
@@ -25,3 +18,10 @@ function debounce(f, ms) {
Пока `isCoolDown` имеет значение `true`, все остальные вызовы игнорируются.
Затем `setTimeout` устанавливает его в `false` после заданной задержки.
+=======
+
+```
+
+A call to `debounce` returns a wrapper. When called, it schedules the original function call after given `ms` and cancels the previous such timeout.
+
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/task.md b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/task.md
index 9c87aa129f..e025d5dbe4 100644
--- a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/task.md
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/task.md
@@ -4,14 +4,22 @@ importance: 5
# Декоратор debounce
+<<<<<<< HEAD
Результатом декоратора `debounce(f, ms)` должна быть обёртка, которая передаёт вызов `f` не более одного раза в `ms` миллисекунд.
Другими словами, когда мы вызываем `debounce`, это гарантирует, что все остальные вызовы будут игнорироваться в течение `ms`.
Например:
+=======
+The result of `debounce(f, ms)` decorator is a wrapper that suspends calls to `f` until there's `ms` milliseconds of inactivity (no calls, "cooldown period"), then invokes `f` once with the latest arguments.
-```js no-beautify
-let f = debounce(alert, 1000);
+In other words, `debounce` is like a secretary that accepts "phone calls", and waits until there's `ms` milliseconds of being quiet. And only then it transfers the latest call information to "the boss" (calls the actual `f`).
+For instance, we had a function `f` and replaced it with `f = debounce(f, 1000)`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
+
+Then if the wrapped function is called at 0ms, 200ms and 500ms, and then there are no calls, then the actual `f` will be only called once, at 1500ms. That is: after the cooldown period of 1000ms from the last call.
+
+<<<<<<< HEAD
f(1); // выполняется немедленно
f(2); // проигнорирован
@@ -21,3 +29,42 @@ setTimeout( () => f(5), 1500); // проигнорирован (прошло т
```
На практике `debounce` полезен для функций, которые получают/обновляют данные, и мы знаем, что повторный вызов в течение короткого промежутка времени не даст ничего нового. Так что лучше не тратить на него ресурсы.
+=======
+
+
+...And it will get the arguments of the very last call, other calls are ignored.
+
+Here's the code for it (uses the debounce decorator from the [Lodash library](https://lodash.com/docs/4.17.15#debounce):
+
+```js
+let f = _.debounce(alert, 1000);
+
+f("a");
+setTimeout( () => f("b"), 200);
+setTimeout( () => f("c"), 500);
+// debounced function waits 1000ms after the last call and then runs: alert("c")
+```
+
+Now a practical example. Let's say, the user types something, and we'd like to send a request to the server when the input is finished.
+
+There's no point in sending the request for every character typed. Instead we'd like to wait, and then process the whole result.
+
+In a web-browser, we can setup an event handler -- a function that's called on every change of an input field. Normally, an event handler is called very often, for every typed key. But if we `debounce` it by 1000ms, then it will be only called once, after 1000ms after the last input.
+
+```online
+
+In this live example, the handler puts the result into a box below, try it:
+
+[iframe border=1 src="debounce" height=200]
+
+See? The second input calls the debounced function, so its content is processed after 1000ms from the last input.
+```
+
+So, `debounce` is a great way to process a sequence of events: be it a sequence of key presses, mouse movements or something else.
+
+It waits the given time after the last call, and then runs its function, that can process the result.
+
+The task is to implement `debounce` decorator.
+
+Hint: that's just a few lines if you think about it :)
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/_js.view/test.js b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/_js.view/test.js
index 46aaa38f47..0c9874dcca 100644
--- a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/_js.view/test.js
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/_js.view/test.js
@@ -7,8 +7,8 @@ describe("throttle(f, 1000)", function() {
}
before(function() {
- f1000 = throttle(f, 1000);
this.clock = sinon.useFakeTimers();
+ f1000 = throttle(f, 1000);
});
it("1-й вызов происходит немедленно", function() {
@@ -45,3 +45,22 @@ describe("throttle(f, 1000)", function() {
});
});
+<<<<<<< HEAD
+=======
+
+describe('throttle', () => {
+
+ it('runs a forwarded call once', done => {
+ let log = '';
+ const f = str => log += str;
+ const f10 = throttle(f, 10);
+ f10('once');
+
+ setTimeout(() => {
+ assert.equal(log, 'once');
+ done();
+ }, 20);
+ });
+
+});
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/solution.md b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/solution.md
index 4d64b9d427..088d9e4274 100644
--- a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/solution.md
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/solution.md
@@ -32,8 +32,14 @@ function throttle(func, ms) {
Вызов `throttle(func, ms)` возвращает `wrapper`.
+<<<<<<< HEAD
1. Во время первого вызова обёртка просто вызывает `func` и устанавливает состояние задержки (`isThrottled = true`).
2. В этом состоянии все вызовы запоминаются в `saveArgs / saveThis`. Обратите внимание, что контекст и аргументы одинаково важны и должны быть запомнены. Они нам нужны для того, чтобы воспроизвести вызов позднее.
3. ... Затем по прошествии `ms` миллисекунд срабатывает `setTimeout`. Состояние задержки сбрасывается (`isThrottled = false`). И если мы проигнорировали вызовы, то "обёртка" выполняется с последними запомненными аргументами и контекстом.
+=======
+1. During the first call, the `wrapper` just runs `func` and sets the cooldown state (`isThrottled = true`).
+2. In this state all calls are memorized in `savedArgs/savedThis`. Please note that both the context and the arguments are equally important and should be memorized. We need them simultaneously to reproduce the call.
+3. After `ms` milliseconds pass, `setTimeout` triggers. The cooldown state is removed (`isThrottled = false`) and, if we had ignored calls, `wrapper` is executed with the last memorized arguments and context.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
На третьем шаге выполняется не `func`, а `wrapper`, потому что нам нужно не только выполнить `func`, но и ещё раз установить состояние задержки и таймаут для его сброса.
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md
index fe5949e7df..9408f511ca 100644
--- a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md
@@ -4,16 +4,33 @@ importance: 5
# Тормозящий (throttling) декоратор
+<<<<<<< HEAD
Создайте "тормозящий" декоратор `throttle(f, ms)`, который возвращает обёртку, передавая вызов в `f` не более одного раза в `ms` миллисекунд. Те вызовы, которые попадают в период "торможения", игнорируются.
**Отличие от `debounce` - если проигнорированный вызов является последним во время "задержки", то он выполняется в конце.**
+=======
+Create a "throttling" decorator `throttle(f, ms)` -- that returns a wrapper.
+
+When it's called multiple times, it passes the call to `f` at maximum once per `ms` milliseconds.
+
+The difference with debounce is that it's completely different decorator:
+- `debounce` runs the function once after the "cooldown" period. Good for processing the final result.
+- `throttle` runs it not more often than given `ms` time. Good for regular updates that shouldn't be very often.
+
+In other words, `throttle` is like a secretary that accepts phone calls, but bothers the boss (calls the actual `f`) not more often than once per `ms` milliseconds.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Давайте рассмотрим реальное применение, чтобы лучше понять это требование и выяснить, откуда оно взято.
**Например, мы хотим отслеживать движения мыши.**
+<<<<<<< HEAD
В браузере мы можем объявить функцию, которая будет запускаться при каждом движении указателя и получать его местоположение. Во время активного использования мыши эта функция запускается очень часто, это может происходить около 100 раз в секунду (каждые 10 мс).
+=======
+In a browser we can setup a function to run at every mouse movement and get the pointer location as it moves. During an active mouse usage, this function usually runs very frequently, can be something like 100 times per second (every 10 ms).
+**We'd like to update some information on the web-page when the pointer moves.**
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
**Мы бы хотели обновлять информацию на странице при передвижениях.**
@@ -32,7 +49,11 @@ importance: 5
```js
function f(a) {
+<<<<<<< HEAD
console.log(a)
+=======
+ console.log(a);
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
}
// f1000 передаёт вызовы f максимум раз в 1000 мс
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/article.md b/1-js/06-advanced-functions/09-call-apply-decorators/article.md
index ede8ee5d73..0cd7e9f82a 100644
--- a/1-js/06-advanced-functions/09-call-apply-decorators/article.md
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/article.md
@@ -76,7 +76,11 @@ let worker = {
},
slow(x) {
+<<<<<<< HEAD
// здесь может быть страшно тяжёлая задача для процессора
+=======
+ // scary CPU-heavy task here
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
alert("Called with " + x);
return x * this.someMethod(); // (*)
}
@@ -150,7 +154,11 @@ function sayHi() {
let user = { name: "John" };
let admin = { name: "Admin" };
+<<<<<<< HEAD
// используем 'call' для передачи различных объектов в качестве 'this'
+=======
+// use call to pass different objects as "this"
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
sayHi.call( user ); // John
sayHi.call( admin ); // Admin
```
@@ -213,7 +221,11 @@ alert( worker.slow(2) ); // работает, не вызывая первона
2. Так что при выполнении `worker.slow(2)` обёртка получает `2` в качестве аргумента и `this=worker` (так как это объект перед точкой).
3. Внутри обёртки, если результат ещё не кеширован, `func.call(this, x)` передаёт текущий `this` (`=worker`) и текущий аргумент (`=2`) в оригинальную функцию.
+<<<<<<< HEAD
## Переходим к нескольким аргументам с "func.apply"
+=======
+## Going multi-argument
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Теперь давайте сделаем `cachingDecorator` ещё более универсальным. До сих пор он работал только с функциями с одним аргументом.
@@ -242,7 +254,11 @@ worker.slow = cachingDecorator(worker.slow);
Для многих практических применений третий вариант достаточно хорош, поэтому мы будем придерживаться его.
+<<<<<<< HEAD
Также нам понадобится заменить `func.call(this, x)` на `func.call(this, ...arguments)`, чтобы передавать все аргументы обёрнутой функции, а не только первый.
+=======
+Also we need to pass not just `x`, but all arguments in `func.call`. Let's recall that in a `function()` we can get a pseudo-array of its arguments as `arguments`, so `func.call(this, x)` should be replaced with `func.call(this, ...arguments)`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Вот более мощный `cachingDecorator`:
@@ -290,7 +306,13 @@ alert( "Again " + worker.slow(3, 5) ); // аналогично (из кеша)
- В строке `(*)` вызываем `hash` для создания одного ключа из `arguments`. Здесь мы используем простую функцию "объединения", которая превращает аргументы `(3, 5)` в ключ `"3,5"`. В более сложных случаях могут потребоваться другие функции хеширования.
- Затем в строке `(**)` используем `func.call(this, ...arguments)` для передачи как контекста, так и всех аргументов, полученных обёрткой (независимо от их количества), в исходную функцию.
+<<<<<<< HEAD
Вместо `func.call(this, ...arguments)` мы могли бы написать `func.apply(this, arguments)`.
+=======
+## func.apply
+
+Instead of `func.call(this, ...arguments)` we could use `func.apply(this, arguments)`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Синтаксис встроенного метода [func.apply](mdn:js/Function/apply):
@@ -305,6 +327,7 @@ func.apply(context, args)
Эти два вызова почти эквивалентны:
```js
+<<<<<<< HEAD
func.call(context, ...args); // передаёт массив как список с оператором расширения
func.apply(context, args); // тот же эффект
```
@@ -317,6 +340,20 @@ func.apply(context, args); // тот же эффект
Так что эти вызовы дополняют друг друга. Для перебираемых объектов сработает `call`, а где мы ожидаем псевдомассив - `apply`.
А если у нас объект, который и то, и другое, например, реальный массив, то технически мы могли бы использовать любой метод, но `apply`, вероятно, будет быстрее, потому что большинство движков JavaScript внутренне оптимизируют его лучше.
+=======
+func.call(context, ...args); // pass an array as list with spread syntax
+func.apply(context, args); // is same as using call
+```
+
+There's only a subtle difference:
+
+- The spread syntax `...` allows to pass *iterable* `args` as the list to `call`.
+- The `apply` accepts only *array-like* `args`.
+
+So, where we expect an iterable, `call` works, and where we expect an array-like, `apply` works.
+
+And for objects that are both iterable and array-like, like a real array, we can use any of them, but `apply` will probably be faster, because most JavaScript engines internally optimize it better.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Передача всех аргументов вместе с контекстом другой функции называется "перенаправлением вызова" (call forwarding).
@@ -350,7 +387,11 @@ function hash(args) {
}
```
+<<<<<<< HEAD
...К сожалению, это не сработает, потому что мы вызываем `hash(arguments)`, а объект `arguments` является перебираемым и псевдомассивом, но не реальным массивом.
+=======
+...Unfortunately, that won't work. Because we are calling `hash(arguments)`, and `arguments` object is both iterable and array-like, but not a real array.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Таким образом, вызов `join` для него потерпит неудачу, что мы и можем видеть ниже:
@@ -376,7 +417,13 @@ function hash() {
hash(1, 2);
```
+<<<<<<< HEAD
Этот трюк называется *заимствование метода*.
+=======
+The trick is called *method borrowing*.
+
+We take (borrow) a join method from a regular array (`[].join`) and use `[].join.call` to run it in the context of `arguments`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Мы берём (заимствуем) метод `join` из обычного массива `[].join`. И используем `[].join.call`, чтобы выполнить его в контексте `arguments`.
diff --git a/1-js/06-advanced-functions/10-bind/6-ask-partial/task.md b/1-js/06-advanced-functions/10-bind/6-ask-partial/task.md
index 7a1ce20c8b..9ef45b77ed 100644
--- a/1-js/06-advanced-functions/10-bind/6-ask-partial/task.md
+++ b/1-js/06-advanced-functions/10-bind/6-ask-partial/task.md
@@ -8,7 +8,11 @@ importance: 5
Объект `user` был изменён. Теперь вместо двух функций `loginOk/loginFail` у него есть только одна -- `user.login(true/false)`.
+<<<<<<< HEAD
Что нужно передать в вызов функции `askPassword` в коде ниже, чтобы она могла вызывать функцию `user.login(true)` как `ok` и функцию `user.login(false)` как `fail`?
+=======
+What should we pass `askPassword` in the code below, so that it calls `user.login(true)` as `ok` and `user.login(false)` as `fail`?
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js
function askPassword(ok, fail) {
diff --git a/1-js/06-advanced-functions/10-bind/article.md b/1-js/06-advanced-functions/10-bind/article.md
index 9b1c8d4731..f189b3dddd 100644
--- a/1-js/06-advanced-functions/10-bind/article.md
+++ b/1-js/06-advanced-functions/10-bind/article.md
@@ -82,10 +82,19 @@ let user = {
setTimeout(() => user.sayHi(), 1000);
+<<<<<<< HEAD
// ...в течение 1 секунды
user = { sayHi() { alert("Другой пользователь в 'setTimeout'!"); } };
// Другой пользователь в 'setTimeout'!
+=======
+// ...the value of user changes within 1 second
+user = {
+ sayHi() { alert("Another user in setTimeout!"); }
+};
+
+// Another user in setTimeout!
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```
Следующее решение гарантирует, что такого не случится.
@@ -97,7 +106,11 @@ user = { sayHi() { alert("Другой пользователь в 'setTimeout'!
Базовый синтаксис `bind`:
```js
+<<<<<<< HEAD
// полный синтаксис будет представлен немного позже
+=======
+// more complex syntax will come a little later
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
let boundFunc = func.bind(context);
```
@@ -157,9 +170,22 @@ let user = {
let sayHi = user.sayHi.bind(user); // (*)
*/!*
+<<<<<<< HEAD
sayHi(); // Привет, Вася!
setTimeout(sayHi, 1000); // Привет, Вася!
+=======
+// can run it without an object
+sayHi(); // Hello, John!
+
+setTimeout(sayHi, 1000); // Hello, John!
+
+// even if the value of user changes within 1 second
+// sayHi uses the pre-bound value which is reference to the old user object
+user = {
+ sayHi() { alert("Another user in setTimeout!"); }
+};
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```
В строке `(*)` мы берём метод `user.sayHi` и привязываем его к `user`. Теперь `sayHi` - это "связанная" функция, которая может быть вызвана отдельно или передана в `setTimeout` (контекст всегда будет правильным).
@@ -191,7 +217,11 @@ for (let key in user) {
}
```
+<<<<<<< HEAD
Некоторые JS-библиотеки предоставляют встроенные функции для удобной массовой привязки контекста, например [_.bindAll(obj)](http://lodash.com/docs#bindAll) в lodash.
+=======
+JavaScript libraries also provide functions for convenient mass binding , e.g. [_.bindAll(object, methodNames)](http://lodash.com/docs#bindAll) in lodash.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
````
## Частичное применение
@@ -267,7 +297,11 @@ alert( triple(5) ); // = mul(3, 5) = 15
Встроенный `bind` не позволяет этого. Мы не можем просто опустить контекст и перейти к аргументам.
+<<<<<<< HEAD
К счастью, легко создать вспомогательную функцию `partial`, которая привязывает только аргументы.
+=======
+Fortunately, a function `partial` for binding only arguments can be easily implemented.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Вот так:
@@ -301,7 +335,11 @@ user.sayNow("Hello");
- Затем передаёт ей `...argsBound` -- аргументы из вызова `partial` (`"10:00"`)
- Затем передаёт ей `...args` -- аргументы, полученные обёрткой (`"Hello"`)
+<<<<<<< HEAD
Благодаря оператору расширения `...` реализовать это очень легко, не правда ли?
+=======
+So easy to do it with the spread syntax, right?
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Также есть готовый вариант [_.partial](https://lodash.com/docs#partial) из библиотеки lodash.
diff --git a/1-js/06-advanced-functions/12-arrow-functions/article.md b/1-js/06-advanced-functions/12-arrow-functions/article.md
index ab10c47396..364fd4fa76 100644
--- a/1-js/06-advanced-functions/12-arrow-functions/article.md
+++ b/1-js/06-advanced-functions/12-arrow-functions/article.md
@@ -119,9 +119,18 @@ function defer(f, ms) {
Стрелочные функции:
+<<<<<<< HEAD
- Не имеют `this`.
- Не имеют `arguments`.
- Не могут быть вызваны с `new`.
- (У них также нет `super`, но мы про это не говорили. Про это будет в главе ).
Всё это потому, что они предназначены для небольшого кода, который не имеет своего "контекста", выполняясь в текущем. И они отлично справляются с этой задачей!
+=======
+- Do not have `this`
+- Do not have `arguments`
+- Can't be called with `new`
+- They also don't have `super`, but we didn't study it yet. We will on the chapter
+
+That's because they are meant for short pieces of code that do not have their own "context", but rather work in the current one. And they really shine in that use case.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
diff --git a/1-js/07-object-properties/01-property-descriptors/article.md b/1-js/07-object-properties/01-property-descriptors/article.md
index 7eb9378f98..f5c6bc81c1 100644
--- a/1-js/07-object-properties/01-property-descriptors/article.md
+++ b/1-js/07-object-properties/01-property-descriptors/article.md
@@ -3,7 +3,11 @@
Как мы знаем, объекты могут содержать свойства.
+<<<<<<< HEAD
До этого момента мы рассматривали свойство только как пару "ключ-значение". Но на самом деле свойство объекта гораздо мощнее и гибче.
+=======
+Until now, a property was a simple "key-value" pair to us. But an object property is actually a more flexible and powerful thing.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
В этой главе мы изучим дополнительные флаги конфигурации для свойств, а в следующей -- увидим, как можно незаметно превратить их в специальные функции - геттеры и сеттеры.
@@ -66,7 +70,11 @@ Object.defineProperty(obj, propertyName, descriptor)
: Объект и его свойство, для которого нужно применить дескриптор.
`descriptor`
+<<<<<<< HEAD
: Применяемый дескриптор.
+=======
+: Property descriptor object to apply.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Если свойство существует, `defineProperty` обновит его флаги. В противном случае метод создаёт новое свойство с указанным значением и флагами; если какой-либо флаг не указан явно, ему присваивается значение `false`.
@@ -134,7 +142,11 @@ let user = { };
Object.defineProperty(user, "name", {
*!*
value: "John",
+<<<<<<< HEAD
// для нового свойства необходимо явно указывать все флаги, для которых значение true
+=======
+ // for new properties we need to explicitly list what's true
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
enumerable: true,
configurable: true
*/!*
@@ -148,7 +160,11 @@ user.name = "Pete"; // Ошибка
Теперь добавим собственный метод `toString` к объекту `user`.
+<<<<<<< HEAD
Встроенный метод `toString` в объектах - неперечислимый, его не видно в цикле `for..in`. Но если мы напишем свой собственный метод `toString`, цикл `for..in` будет выводить его по умолчанию:
+=======
+Normally, a built-in `toString` for objects is non-enumerable, it does not show up in `for..in`. But if we add a `toString` of our own, then by default it shows up in `for..in`, like this:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js run
let user = {
@@ -162,7 +178,11 @@ let user = {
for (let key in user) alert(key); // name, toString
```
+<<<<<<< HEAD
Если мы этого не хотим, можно установить для свойства `enumerable:false`. Тогда оно перестанет появляться в цикле `for..in` аналогично встроенному `toString`:
+=======
+If we don't like it, then we can set `enumerable:false`. Then it won't appear in a `for..in` loop, just like the built-in one:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js run
let user = {
diff --git a/1-js/07-object-properties/02-property-accessors/article.md b/1-js/07-object-properties/02-property-accessors/article.md
index 023449fa6f..1749631f0b 100644
--- a/1-js/07-object-properties/02-property-accessors/article.md
+++ b/1-js/07-object-properties/02-property-accessors/article.md
@@ -1,11 +1,19 @@
# Свойства - геттеры и сеттеры
+<<<<<<< HEAD
Есть два типа свойств объекта.
Первый тип это *свойства-данные (data properties)*. Мы уже знаем, как работать с ними. Все свойства, которые мы использовали до текущего момента, были свойствами-данными.
Второй тип свойств мы ещё не рассматривали. Это *свойства-аксессоры (accessor properties)*. По своей сути это функции, которые используются для присвоения и получения значения, но во внешнем коде они выглядят как обычные свойства объекта.
+=======
+There are two kinds of object properties.
+
+The first kind is *data properties*. We already know how to work with them. All properties that we've been using until now were data properties.
+
+The second type of properties is something new. It's *accessor properties*. They are essentially functions that execute on getting and setting a value, but look like regular properties to an external code.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
## Геттеры и сеттеры
@@ -53,7 +61,13 @@ alert(user.fullName); // John Smith
*/!*
```
+<<<<<<< HEAD
Снаружи свойство-аксессор выглядит как обычное свойство. В этом и заключается смысл свойств-аксессоров. Мы не *вызываем* `user.fullName` как функцию, а *читаем* как обычное свойство: геттер выполнит всю работу за кулисами.
+=======
+From the outside, an accessor property looks like a regular one. That's the idea of accessor properties. We don't *call* `user.fullName` as a function, we *read* it normally: the getter runs behind the scenes.
+
+As of now, `fullName` has only a getter. If we attempt to assign `user.fullName=`, there will be an error:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js run
let user = {
@@ -92,7 +106,11 @@ alert(user.name); // Alice
alert(user.surname); // Cooper
```
+<<<<<<< HEAD
В итоге мы получили "виртуальное" свойство `fullName`. Его можно прочитать и изменить.
+=======
+As the result, we have a "virtual" property `fullName`. It is readable and writable.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
## Дескрипторы свойств доступа
@@ -132,7 +150,11 @@ alert(user.fullName); // John Smith
for(let key in user) alert(key); // name, surname
```
+<<<<<<< HEAD
Ещё раз заметим, что свойство объекта может быть либо свойством-аксессором (с методами `get/set`), либо свойством-данным (со значением `value`).
+=======
+Please note that a property can be either an accessor (has `get/set` methods) or a data property (has a `value`), not both.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
При попытке указать и `get`, и `value` в одном дескрипторе будет ошибка:
@@ -183,9 +205,15 @@ user.name = ""; // Имя слишком короткое...
## Использование для совместимости
+<<<<<<< HEAD
У аксессоров есть интересная область применения - они позволяют в любой момент взять "обычное" свойство и изменить его поведение, поменяв на геттер и сеттер.
Например, представим, что мы начали реализовывать объект `user`, используя свойства-данные имя `name` и возраст `age`:
+=======
+One of the great uses of accessors is that they allow to take control over a "regular" data property at any moment by replacing it with a getter and a setter and tweak its behavior.
+
+Imagine we started implementing user objects using data properties `name` and `age`:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js
function User(name, age) {
diff --git a/1-js/08-prototypes/01-prototype-inheritance/2-search-algorithm/task.md b/1-js/08-prototypes/01-prototype-inheritance/2-search-algorithm/task.md
index 136a2c94b8..4b603eec5b 100644
--- a/1-js/08-prototypes/01-prototype-inheritance/2-search-algorithm/task.md
+++ b/1-js/08-prototypes/01-prototype-inheritance/2-search-algorithm/task.md
@@ -6,7 +6,11 @@ importance: 5
Задача состоит из двух частей.
+<<<<<<< HEAD
У нас есть объекты:
+=======
+Given the following objects:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js
let head = {
diff --git a/1-js/08-prototypes/01-prototype-inheritance/3-proto-and-this/task.md b/1-js/08-prototypes/01-prototype-inheritance/3-proto-and-this/task.md
index bf6f151b1e..0f3e0dd909 100644
--- a/1-js/08-prototypes/01-prototype-inheritance/3-proto-and-this/task.md
+++ b/1-js/08-prototypes/01-prototype-inheritance/3-proto-and-this/task.md
@@ -2,7 +2,11 @@ importance: 5
---
+<<<<<<< HEAD
# Куда будет произведена запись?
+=======
+# Where does it write?
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Объект `rabbit` наследует от объекта `animal`.
diff --git a/1-js/08-prototypes/01-prototype-inheritance/4-hamster-proto/task.md b/1-js/08-prototypes/01-prototype-inheritance/4-hamster-proto/task.md
index 2c8d5ceae1..d871453914 100644
--- a/1-js/08-prototypes/01-prototype-inheritance/4-hamster-proto/task.md
+++ b/1-js/08-prototypes/01-prototype-inheritance/4-hamster-proto/task.md
@@ -2,11 +2,19 @@ importance: 5
---
+<<<<<<< HEAD
# Почему наедаются оба хомяка?
+=======
+# Why are both hamsters full?
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
У нас есть два хомяка: шустрый (`speedy`) и ленивый (`lazy`); оба наследуют от общего объекта `hamster`.
+<<<<<<< HEAD
Когда мы кормим одного хомяка, второй тоже наедается. Почему? Как это исправить?
+=======
+When we feed one of them, the other one is also full. Why? How can we fix it?
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js run
let hamster = {
diff --git a/1-js/08-prototypes/01-prototype-inheritance/article.md b/1-js/08-prototypes/01-prototype-inheritance/article.md
index eb354126cb..df63a2d46e 100644
--- a/1-js/08-prototypes/01-prototype-inheritance/article.md
+++ b/1-js/08-prototypes/01-prototype-inheritance/article.md
@@ -16,7 +16,11 @@
Свойство `[[Prototype]]` является внутренним и скрытым, но есть много способов задать его.
+<<<<<<< HEAD
Одним из них является использование `__proto__`, например так:
+=======
+One of them is to use the special name `__proto__`, like this:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js run
let animal = {
@@ -31,10 +35,17 @@ rabbit.__proto__ = animal;
*/!*
```
+<<<<<<< HEAD
```smart header="Свойство `__proto__` — исторически обусловленный геттер/сеттер для `[[Prototype]]`"
Обратите внимание, что `__proto__` — *не то же самое*, что `[[Prototype]]`. Это геттер/сеттер для него.
Он существует по историческим причинам, в современном языке его заменяют функции `Object.getPrototypeOf/Object.setPrototypeOf`, которые также получают/устанавливают прототип. Мы рассмотрим причины этого и сами функции позже.
+=======
+```smart header="`__proto__` is a historical getter/setter for `[[Prototype]]`"
+Please note that `__proto__` is *not the same* as `[[Prototype]]`. It's a getter/setter for it.
+
+It exists for historical reasons. In modern language it is replaced with functions `Object.getPrototypeOf/Object.setPrototypeOf` that also get/set the prototype. We'll study the reasons for that and these functions later.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
По спецификации `__proto__` должен поддерживаться только браузерами, но по факту все среды, включая серверную, поддерживают его. Далее мы будем в примерах использовать `__proto__`, так как это самый короткий и интуитивно понятный способ установки и чтения прототипа.
```
@@ -43,7 +54,7 @@ rabbit.__proto__ = animal;
Например:
-```js run
+```js
let animal = {
eats: true
};
@@ -197,15 +208,25 @@ alert(admin.fullName); // John Smith (*)
// срабатывает сеттер!
admin.fullName = "Alice Cooper"; // (**)
+<<<<<<< HEAD
alert(admin.name); // Alice
alert(admin.surname); // Cooper
+=======
+
+alert(admin.fullName); // Alice Cooper , state of admin modified
+alert(user.fullName); // John Smith , state of user protected
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```
Здесь в строке `(*)` свойство `admin.fullName` имеет геттер в прототипе `user`, поэтому вызывается он. В строке `(**)` свойство также имеет сеттер в прототипе, который и будет вызван.
## Значение "this"
+<<<<<<< HEAD
В приведённом выше примере может возникнуть интересный вопрос: каково значение `this` внутри `set fullName(value)`? Куда записаны свойства `this.name` и `this.surname`: в `user` или в `admin`?
+=======
+An interesting question may arise in the example above: what's the value of `this` inside `set fullName(value)`? Where are the properties `this.name` and `this.surname` written: into `user` or `admin`?
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Ответ прост: прототипы никак не влияют на `this`.
@@ -213,7 +234,11 @@ alert(admin.surname); // Cooper
Таким образом, вызов сеттера `admin.fullName=` в качестве `this` использует `admin`, а не `user`.
+<<<<<<< HEAD
Это на самом деле очень важная деталь, потому что у нас может быть большой объект со множеством методов, от которого можно наследовать. Затем наследующие объекты могут вызывать его методы, но они будут изменять своё состояние, а не состояние объекта-родителя.
+=======
+That is actually a super-important thing, because we may have a big object with many methods, and have objects that inherit from it. And when the inheriting objects run the inherited methods, they will modify only their own states, not the state of the big object.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Например, здесь `animal` представляет собой "хранилище методов", и `rabbit` использует его.
@@ -248,13 +273,21 @@ alert(animal.isSleeping); // undefined (нет такого свойства в

+<<<<<<< HEAD
Если бы у нас были другие объекты, такие как `bird`, `snake` и т.д., унаследованные от `animal`, они также получили бы доступ к методам `animal`. Но `this` при вызове каждого метода будет соответствовать объекту (перед точкой), на котором происходит вызов, а не `animal`. Поэтому, когда мы записываем данные в `this`, они сохраняются в этих объектах.
+=======
+If we had other objects, like `bird`, `snake`, etc., inheriting from `animal`, they would also gain access to methods of `animal`. But `this` in each method call would be the corresponding object, evaluated at the call-time (before dot), not `animal`. So when we write data into `this`, it is stored into these objects.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
В результате методы являются общими, а состояние объекта — нет.
## Цикл for..in
+<<<<<<< HEAD
Цикл `for..in` проходит не только по собственным, но и по унаследованным свойствам объекта.
+=======
+The `for..in` loop iterates over inherited properties too.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Например:
@@ -269,7 +302,11 @@ let rabbit = {
};
*!*
+<<<<<<< HEAD
// Object.keys возвращает только собственные ключи
+=======
+// Object.keys only returns own keys
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
alert(Object.keys(rabbit)); // jumps
*/!*
diff --git a/1-js/08-prototypes/02-function-prototype/1-changing-prototype/task.md b/1-js/08-prototypes/02-function-prototype/1-changing-prototype/task.md
index 613f6c1b81..7e3aab06ad 100644
--- a/1-js/08-prototypes/02-function-prototype/1-changing-prototype/task.md
+++ b/1-js/08-prototypes/02-function-prototype/1-changing-prototype/task.md
@@ -20,7 +20,11 @@ alert( rabbit.eats ); // true
```
+<<<<<<< HEAD
1. Добавим одну строчку (выделенную в коде ниже). Что вызов `alert` покажет нам сейчас?
+=======
+1. We added one more string (emphasized). What will `alert` show now?
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js
function Rabbit() {}
@@ -54,7 +58,11 @@ alert( rabbit.eats ); // true
alert( rabbit.eats ); // ?
```
+<<<<<<< HEAD
3. Или такой (заменили одну строчку)?
+=======
+3. And like this (replaced one line)?
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js
function Rabbit() {}
diff --git a/1-js/08-prototypes/02-function-prototype/4-new-object-same-constructor/solution.md b/1-js/08-prototypes/02-function-prototype/4-new-object-same-constructor/solution.md
index ca15792760..dedea090c5 100644
--- a/1-js/08-prototypes/02-function-prototype/4-new-object-same-constructor/solution.md
+++ b/1-js/08-prototypes/02-function-prototype/4-new-object-same-constructor/solution.md
@@ -15,7 +15,11 @@ alert( user2.name ); // Pete (сработало!)
Всё получилось, потому что `User.prototype.constructor == User`.
+<<<<<<< HEAD
...Но если кто-то перезапишет `User.prototype` и забудет заново назначить свойство `"constructor"`, чтобы оно указывало на `User`, то ничего не выйдет.
+=======
+..But if someone, so to speak, overwrites `User.prototype` and forgets to recreate `constructor` to reference `User`, then it would fail.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Например:
@@ -41,4 +45,8 @@ alert( user2.name ); // undefined
2. Потом задействуется поиск по цепочке прототипов. Прототип объекта `user` -- это `User.prototype`, и там тоже нет искомого свойства.
3. Значение `User.prototype` -- это пустой объект `{}`, чей прототип -- `Object.prototype`. `Object.prototype.constructor == Object`. Таким образом, свойство `constructor` всё-таки найдено.
+<<<<<<< HEAD
Наконец срабатывает `let user2 = new Object('Pete')`, но конструктор `Object` игнорирует аргументы, он всегда создаёт пустой объект: `let user2 = {}` -- это как раз то, чему равен `user2` в итоге.
+=======
+At the end, we have `let user2 = new Object('Pete')`. The built-in `Object` constructor ignores arguments, it always creates an empty object, similar to `let user2 = {}`, that's what we have in `user2` after all.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
diff --git a/1-js/08-prototypes/02-function-prototype/article.md b/1-js/08-prototypes/02-function-prototype/article.md
index fd3ab2f6ce..0becc98981 100644
--- a/1-js/08-prototypes/02-function-prototype/article.md
+++ b/1-js/08-prototypes/02-function-prototype/article.md
@@ -2,7 +2,11 @@
Как мы помним, новые объекты могут быть созданы с помощью функции-конструктора `new F()`.
+<<<<<<< HEAD
Если в `F.prototype` содержится объект, оператор `new` устанавливает его в качестве `[[Prototype]]` для нового объекта.
+=======
+If `F.prototype` is an object, then the `new` operator uses it to set `[[Prototype]]` for the new object.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```smart
JavaScript использовал прототипное наследование с момента своего появления. Это одна из основных особенностей языка.
@@ -40,8 +44,13 @@ alert( rabbit.eats ); // true
На изображении: `"prototype"` - горизонтальная стрелка, обозначающая обычное свойство для `"F"`, а `[[Prototype]]` -- вертикальная, обозначающая наследование `rabbit` от `animal`.
+<<<<<<< HEAD
```smart header="`F.prototype` используется только в момент вызова `new F()`"
`F.prototype` используется только при вызове `new F()` и присваивается в качестве свойства `[[Prototype]]` нового объекта. После этого `F.prototype` и новый объект ничего не связывает. Следует понимать это как "единоразовый подарок" объекту.
+=======
+```smart header="`F.prototype` only used at `new F` time"
+`F.prototype` property is only used when `new F` is called, it assigns `[[Prototype]]` of the new object.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
После создания `F.prototype` может измениться, и новые объекты, созданные с помощью `new F()`, будут иметь другой объект в качестве `[[Prototype]]`, но уже существующие объекты сохранят старый.
```
@@ -158,11 +167,19 @@ Rabbit.prototype = {
В этой главе мы кратко описали способ задания `[[Prototype]]` для объектов, создаваемых с помощью функции-конструктора. Позже мы рассмотрим, как можно использовать эту возможность.
+<<<<<<< HEAD
Всё достаточно просто. Выделим основные моменты:
- Свойство `F.prototype` (не путать с `[[Prototype]]`) устанавливает`[[Prototype]]` для новых объектов при вызове `new F()`.
- Значение `F.prototype` должно быть либо объектом, либо `null`. Другие значения не будут работать.
- Свойство `"prototype"` является особым, только когда оно назначено функции-конструктору, которая вызывается оператором `new`.
+=======
+Everything is quite simple, just a few notes to make things clear:
+
+- The `F.prototype` property (don't mistake it for `[[Prototype]]`) sets `[[Prototype]]` of new objects when `new F()` is called.
+- The value of `F.prototype` should be either an object or `null`: other values won't work.
+- The `"prototype"` property only has such a special effect when set on a constructor function, and invoked with `new`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
В обычных объектах `prototype` не является чем-то особенным:
```js
diff --git a/1-js/08-prototypes/03-native-prototypes/2-defer-to-prototype-extended/solution.md b/1-js/08-prototypes/03-native-prototypes/2-defer-to-prototype-extended/solution.md
index a2d8851bc4..3f0fe0596d 100644
--- a/1-js/08-prototypes/03-native-prototypes/2-defer-to-prototype-extended/solution.md
+++ b/1-js/08-prototypes/03-native-prototypes/2-defer-to-prototype-extended/solution.md
@@ -15,3 +15,27 @@ function f(a, b) {
f.defer(1000)(1, 2); // выведет 3 через 1 секунду.
```
+
+Please note: we use `this` in `f.apply` to make our decoration work for object methods.
+
+So if the wrapper function is called as an object method, then `this` is passed to the original method `f`.
+
+```js run
+Function.prototype.defer = function(ms) {
+ let f = this;
+ return function(...args) {
+ setTimeout(() => f.apply(this, args), ms);
+ }
+};
+
+let user = {
+ name: "John",
+ sayHi() {
+ alert(this.name);
+ }
+}
+
+user.sayHi = user.sayHi.defer(1000);
+
+user.sayHi();
+```
diff --git a/1-js/08-prototypes/03-native-prototypes/article.md b/1-js/08-prototypes/03-native-prototypes/article.md
index 035ff13fc7..f5411867e3 100644
--- a/1-js/08-prototypes/03-native-prototypes/article.md
+++ b/1-js/08-prototypes/03-native-prototypes/article.md
@@ -99,12 +99,21 @@ alert(f.__proto__.__proto__ == Object.prototype); // true, наследует о
Самое сложное происходит со строками, числами и булевыми значениями.
+<<<<<<< HEAD
Как мы помним, они не объекты. Но если мы попытаемся получить доступ к их свойствам, то тогда будет создан временный объект-обёртка с использованием встроенных конструкторов `String`, `Number` и `Boolean`, который предоставит методы и после этого исчезнет.
+=======
+As we remember, they are not objects. But if we try to access their properties, temporary wrapper objects are created using built-in constructors `String`, `Number` and `Boolean`. They provide the methods and disappear.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Эти объекты создаются невидимо для нас, и большая часть движков оптимизирует этот процесс, но спецификация описывает это именно таким образом. Методы этих объектов также находятся в прототипах, доступных как `String.prototype`, `Number.prototype` и `Boolean.prototype`.
+<<<<<<< HEAD
```warn header="Значения `null` и `undefined` не имеют объектов-обёрток"
Специальные значения `null` и `undefined` стоят особняком. У них нет объектов-обёрток, так что методы и свойства им недоступны. Также у них нет соответствующих прототипов.
+=======
+```warn header="Values `null` and `undefined` have no object wrappers"
+Special values `null` and `undefined` stand apart. They have no object wrappers, so methods and properties are not available for them. And there are no corresponding prototypes either.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```
## Изменение встроенных прототипов [#native-prototype-change]
@@ -129,9 +138,15 @@ String.prototype.show = function() {
**В современном программировании есть только один случай, в котором одобряется изменение встроенных прототипов. Это создание полифилов.**
+<<<<<<< HEAD
Полифил - это термин, который означает эмуляцию метода, который существует в спецификации JavaScript, но ещё не поддерживается текущим движком JavaScript.
Тогда мы можем реализовать его сами и добавить во встроенный прототип.
+=======
+Polyfilling is a term for making a substitute for a method that exists in the JavaScript specification, but is not yet supported by a particular JavaScript engine.
+
+We may then implement it manually and populate the built-in prototype with it.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Например:
@@ -142,9 +157,15 @@ if (!String.prototype.repeat) { // Если такого метода нет
String.prototype.repeat = function(n) {
// повторить строку n раз
+<<<<<<< HEAD
// на самом деле код должен быть немного более сложным
// (полный алгоритм можно найти в спецификации)
// но даже неполный полифил зачастую достаточно хорош для использования
+=======
+ // actually, the code should be a little bit more complex than that
+ // (the full algorithm is in the specification)
+ // but even an imperfect polyfill is often considered good enough
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
return new Array(n + 1).join(this);
};
}
@@ -179,18 +200,34 @@ obj.join = Array.prototype.join;
alert( obj.join(',') ); // Hello,world!
```
+<<<<<<< HEAD
Это работает, потому что для внутреннего алгоритма встроенного метода `join` важны только корректность индексов и свойство `length`, он не проверяет, является ли объект на самом деле массивом. И многие встроенные методы работают так же.
+=======
+It works because the internal algorithm of the built-in `join` method only cares about the correct indexes and the `length` property. It doesn't check if the object is indeed an array. Many built-in methods are like that.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Альтернативная возможность - мы можем унаследовать от массива, установив `obj.__proto__` как `Array.prototype`, таким образом все методы `Array` станут автоматически доступны в `obj`.
Но это будет невозможно, если `obj` уже наследует от другого объекта. Помните, мы можем наследовать только от одного объекта одновременно.
+<<<<<<< HEAD
Заимствование методов - гибкий способ, позволяющий смешивать функциональность разных объектов по необходимости.
+=======
+Borrowing methods is flexible, it allows to mix functionalities from different objects if needed.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
## Итого
+<<<<<<< HEAD
- Все встроенные объекты следуют одному шаблону:
- Методы хранятся в прототипах (`Array.prototype`, `Object.prototype`, `Date.prototype` и т.д.).
- Сами объекты хранят только данные (элементы массивов, свойства объектов, даты).
- Примитивы также хранят свои методы в прототипах объектов-обёрток: `Number.prototype`, `String.prototype`, `Boolean.prototype`. Только у значений `undefined` и `null` нет объектов-обёрток.
- Встроенные прототипы могут быть изменены или дополнены новыми методами. Но не рекомендуется менять их. Единственная допустимая причина -- это добавление нового метода из стандарта, который ещё не поддерживается движком JavaScript.
+=======
+- All built-in objects follow the same pattern:
+ - The methods are stored in the prototype (`Array.prototype`, `Object.prototype`, `Date.prototype`, etc.)
+ - The object itself stores only the data (array items, object properties, the date)
+- Primitives also store methods in prototypes of wrapper objects: `Number.prototype`, `String.prototype` and `Boolean.prototype`. Only `undefined` and `null` do not have wrapper objects
+- Built-in prototypes can be modified or populated with new methods. But it's not recommended to change them. The only allowable case is probably when we add-in a new standard, but it's not yet supported by the JavaScript engine
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
diff --git a/1-js/08-prototypes/04-prototype-methods/article.md b/1-js/08-prototypes/04-prototype-methods/article.md
index bd0ee42c16..8fe99dfd20 100644
--- a/1-js/08-prototypes/04-prototype-methods/article.md
+++ b/1-js/08-prototypes/04-prototype-methods/article.md
@@ -7,9 +7,15 @@
Современные же методы это:
+<<<<<<< HEAD
- [Object.create(proto, [descriptors])](mdn:js/Object/create) -- создаёт пустой объект со свойством `[[Prototype]]`, указанным как `proto`, и необязательными дескрипторами свойств `descriptors`.
- [Object.getPrototypeOf(obj)](mdn:js/Object/getPrototypeOf) -- возвращает свойство `[[Prototype]]` объекта `obj`.
- [Object.setPrototypeOf(obj, proto)](mdn:js/Object/setPrototypeOf) -- устанавливает свойство `[[Prototype]]` объекта `obj` как `proto`.
+=======
+- [Object.create(proto, [descriptors])](mdn:js/Object/create) -- creates an empty object with given `proto` as `[[Prototype]]` and optional property descriptors.
+- [Object.getPrototypeOf(obj)](mdn:js/Object/getPrototypeOf) -- returns the `[[Prototype]]` of `obj`.
+- [Object.setPrototypeOf(obj, proto)](mdn:js/Object/setPrototypeOf) -- sets the `[[Prototype]]` of `obj` to `proto`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Эти методы нужно использовать вместо `__proto__`.
@@ -28,7 +34,11 @@ let rabbit = Object.create(animal);
alert(rabbit.eats); // true
*!*
+<<<<<<< HEAD
alert(Object.getPrototypeOf(rabbit) === animal); // получаем прототип объекта rabbit
+=======
+alert(Object.getPrototypeOf(rabbit) === animal); // true
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
*/!*
*!*
@@ -57,7 +67,10 @@ alert(rabbit.jumps); // true
Мы также можем использовать `Object.create` для "продвинутого" клонирования объекта, более мощного, чем копирование свойств в цикле `for..in`:
```js
+<<<<<<< HEAD
// клон obj c тем же прототипом (с поверхностным копированием свойств)
+=======
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
let clone = Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj));
```
@@ -65,24 +78,43 @@ let clone = Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescr
## Краткая история
+<<<<<<< HEAD
Если пересчитать все способы управления прототипом, то их будет много! И многие из них делают одно и то же!
Почему так?
+=======
+If we count all the ways to manage `[[Prototype]]`, there are a lot! Many ways to do the same thing!
+
+Why?
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
В силу исторических причин.
+<<<<<<< HEAD
- Свойство `"prototype"` функции-конструктора существует с совсем давних времён.
- Позднее, в 2012 году, в стандарте появился метод `Object.create`. Это давало возможность создавать объекты с указанным прототипом, но не позволяло устанавливать/получать его. Тогда браузеры реализовали нестандартный аксессор `__proto__`, который позволил устанавливать/получать прототип в любое время.
- Позднее, в 2015 году, в стандарт были добавлены `Object.setPrototypeOf` и `Object.getPrototypeOf,` заменяющие собой аксессор `__proto__`, который упоминается в Приложении Б стандарта, которое не обязательно к поддержке в небраузерных окружениях. При этом де-факто `__proto__` всё ещё поддерживается везде.
+=======
+- The `"prototype"` property of a constructor function has worked since very ancient times.
+- Later, in the year 2012, `Object.create` appeared in the standard. It gave the ability to create objects with a given prototype, but did not provide the ability to get/set it. So browsers implemented the non-standard `__proto__` accessor that allowed the user to get/set a prototype at any time.
+- Later, in the year 2015, `Object.setPrototypeOf` and `Object.getPrototypeOf` were added to the standard, to perform the same functionality as `__proto__`. As `__proto__` was de-facto implemented everywhere, it was kind-of deprecated and made its way to the Annex B of the standard, that is: optional for non-browser environments.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
В итоге сейчас у нас есть все эти способы для работы с прототипом.
Почему же `__proto__` был заменён на функции `getPrototypeOf/setPrototypeOf`? Читайте далее, чтобы узнать ответ.
+<<<<<<< HEAD
```warn header="Не меняйте `[[Prototype]]` существующих объектов, если важна скорость"
Технически мы можем установить/получить `[[Prototype]]` в любое время. Но обычно мы устанавливаем прототип только раз во время создания объекта, а после не меняем: `rabbit` наследует от `animal`, и это не изменится.
И JavaScript движки хорошо оптимизированы для этого. Изменение прототипа "на лету" с помощью `Object.setPrototypeOf` или `obj.__proto__=` - очень медленная операция, которая ломает внутренние оптимизации для операций доступа к свойствам объекта. Так что лучше избегайте этого кроме тех случаев, когда вы знаете, что делаете, или же когда скорость JavaScript для вас не имеет никакого значения.
+=======
+```warn header="Don't change `[[Prototype]]` on existing objects if speed matters"
+Technically, we can get/set `[[Prototype]]` at any time. But usually we only set it once at the object creation time and don't modify it anymore: `rabbit` inherits from `animal`, and that is not going to change.
+
+And JavaScript engines are highly optimized for this. Changing a prototype "on-the-fly" with `Object.setPrototypeOf` or `obj.__proto__=` is a very slow operation as it breaks internal optimizations for object property access operations. So avoid it unless you know what you're doing, or JavaScript speed totally doesn't matter for you.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```
## "Простейший" объект [#very-plain]
@@ -102,18 +134,29 @@ obj[key] = "some value";
alert(obj[key]); // [object Object], не "some value"!
```
+<<<<<<< HEAD
Если пользователь введёт `__proto__`, присвоение проигнорируется!
И это не должно удивлять нас. Свойство `__proto__` особенное: оно должно быть либо объектом, либо `null`, а строка не может стать прототипом.
+=======
+Here, if the user types in `__proto__`, the assignment is ignored!
+
+That shouldn't surprise us. The `__proto__` property is special: it must be either an object or `null`. A string can not become a prototype.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Но мы не *намеревались* реализовывать такое поведение, не так ли? Мы хотим хранить пары ключ/значение, и ключ с именем `"__proto__"` не был сохранён надлежащим образом. Так что это ошибка!
+<<<<<<< HEAD
Конкретно в этом примере последствия не так ужасны, но если мы присваиваем объектные значения, то прототип и в самом деле может быть изменён. В результате дальнейшее выполнение пойдёт совершенно непредсказуемым образом.
+=======
+Here the consequences are not terrible. But in other cases we may be assigning object values, and then the prototype may indeed be changed. As a result, the execution will go wrong in totally unexpected ways.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Что хуже всего -- разработчики не задумываются о такой возможности совсем. Это делает такие ошибки сложным для отлавливания или даже превращает их в уязвимости, особенно когда JavaScript используется на сервере.
Неожиданные вещи могут случаться также при присвоении свойства `toString`, которое по умолчанию функция, и других свойств, которые тоже на самом деле являются встроенными методами.
+<<<<<<< HEAD
Как же избежать проблемы?
Во-первых, мы можем переключиться на использование коллекции `Map`, и тогда всё будет в порядке.
@@ -121,6 +164,15 @@ alert(obj[key]); // [object Object], не "some value"!
Но и `Object` может также хорошо подойти, потому что создатели языка уже давно продумали решение проблемы.
Свойство `__proto__` -- не обычное, а аксессор, заданный в `Object.prototype`:
+=======
+How can we avoid this problem?
+
+First, we can just switch to using `Map` for storage instead of plain objects, then everything's fine.
+
+But `Object` can also serve us well here, because language creators gave thought to that problem long ago.
+
+`__proto__` is not a property of an object, but an accessor property of `Object.prototype`:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a

@@ -128,7 +180,11 @@ alert(obj[key]); // [object Object], не "some value"!
Как было сказано в начале этой секции учебника, `__proto__` -- это способ доступа к свойству `[[Prototype]]`, это не само свойство `[[Prototype]]`.
+<<<<<<< HEAD
Теперь, если мы хотим использовать объект как ассоциативный массив, мы можем сделать это с помощью небольшого трюка:
+=======
+Now, if we intend to use an object as an associative array and be free of such problems, we can do it with a little trick:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js run
*!*
@@ -147,7 +203,11 @@ alert(obj[key]); // "some value"
Таким образом не будет унаследованного геттера/сеттера для `__proto__`. Теперь это свойство обрабатывается как обычное свойство, и приведённый выше пример работает правильно.
+<<<<<<< HEAD
Мы можем назвать такой объект "простейшим" или "чистым словарным объектом", потому что он ещё проще, чем обычные объекты `{...}`.
+=======
+We can call such objects "very plain" or "pure dictionary" objects, because they are even simpler than the regular plain object `{...}`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Недостаток в том, что у таких объектов не будет встроенных методов объекта, таких как `toString`:
@@ -174,6 +234,7 @@ alert(Object.keys(chineseDictionary)); // hello,bye
## Итого
+<<<<<<< HEAD
Современные способы установки и прямого доступа к прототипу это:
- [Object.create(proto[, descriptors])](mdn:js/Object/create) -- создаёт пустой объект со свойством `[[Prototype]]`, указанным как `proto` (может быть `null`), и необязательными дескрипторами свойств.
@@ -181,6 +242,15 @@ alert(Object.keys(chineseDictionary)); // hello,bye
- [Object.setPrototypeOf(obj, proto)](mdn:js/Object.setPrototypeOf) -- устанавливает свойство `[[Prototype]]` объекта `obj` как `proto` (то же самое, что и сеттер `__proto__`).
Встроенный геттер/сеттер `__proto__` не безопасен, если мы хотим использовать *созданные пользователями* ключи в объекте. Как минимум потому, что пользователь может ввести `"__proto__"` как ключ, от чего может возникнуть ошибка. Если повезёт - последствия будут лёгкими, но, вообще говоря, они непредсказуемы.
+=======
+Modern methods to set up and directly access the prototype are:
+
+- [Object.create(proto, [descriptors])](mdn:js/Object/create) -- creates an empty object with a given `proto` as `[[Prototype]]` (can be `null`) and optional property descriptors.
+- [Object.getPrototypeOf(obj)](mdn:js/Object.getPrototypeOf) -- returns the `[[Prototype]]` of `obj` (same as `__proto__` getter).
+- [Object.setPrototypeOf(obj, proto)](mdn:js/Object.setPrototypeOf) -- sets the `[[Prototype]]` of `obj` to `proto` (same as `__proto__` setter).
+
+The built-in `__proto__` getter/setter is unsafe if we'd want to put user-generated keys into an object. Just because a user may enter `"__proto__"` as the key, and there'll be an error, with hopefully light, but generally unpredictable consequences.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Так что мы можем использовать либо `Object.create(null)` для создания "простейшего" объекта, либо использовать коллекцию `Map`.
@@ -196,6 +266,7 @@ let clone = Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescr
Ещё методы:
+<<<<<<< HEAD
- [Object.keys(obj)](mdn:js/Object/keys) / [Object.values(obj)](mdn:js/Object/values) / [Object.entries(obj)](mdn:js/Object/entries) -- возвращают массив всех перечисляемых собственных строковых ключей/значений/пар ключ-значение.
- [Object.getOwnPropertySymbols(obj)](mdn:js/Object/getOwnPropertySymbols) -- возвращает массив всех собственных символьных ключей.
- [Object.getOwnPropertyNames(obj)](mdn:js/Object/getOwnPropertyNames) -- возвращает массив всех собственных строковых ключей.
@@ -203,3 +274,12 @@ let clone = Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescr
- [obj.hasOwnProperty(key)](mdn:js/Object/hasOwnProperty): возвращает `true`, если у `obj` есть собственное (не унаследованное) свойство с именем `key`.
Все методы, которые возвращают свойства объектов (такие как `Object.keys` и другие), возвращают "собственные" свойства. Если мы хотим получить и унаследованные, можно воспользоваться циклом `for..in`.
+=======
+- [Object.keys(obj)](mdn:js/Object/keys) / [Object.values(obj)](mdn:js/Object/values) / [Object.entries(obj)](mdn:js/Object/entries) -- returns an array of enumerable own string property names/values/key-value pairs.
+- [Object.getOwnPropertySymbols(obj)](mdn:js/Object/getOwnPropertySymbols) -- returns an array of all own symbolic keys.
+- [Object.getOwnPropertyNames(obj)](mdn:js/Object/getOwnPropertyNames) -- returns an array of all own string keys.
+- [Reflect.ownKeys(obj)](mdn:js/Reflect/ownKeys) -- returns an array of all own keys.
+- [obj.hasOwnProperty(key)](mdn:js/Object/hasOwnProperty): returns `true` if `obj` has its own (not inherited) key named `key`.
+
+All methods that return object properties (like `Object.keys` and others) -- return "own" properties. If we want inherited ones, we can use `for..in`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
diff --git a/1-js/09-classes/01-class/article.md b/1-js/09-classes/01-class/article.md
index bbe95c6f49..bb38834e79 100644
--- a/1-js/09-classes/01-class/article.md
+++ b/1-js/09-classes/01-class/article.md
@@ -67,7 +67,11 @@ user.sayHi();
Давайте развеем всю магию и посмотрим, что такое класс на самом деле. Это поможет в понимании многих сложных аспектов.
+<<<<<<< HEAD
В JavaScript класс - это разновидность функции.
+=======
+In JavaScript, a class is a kind of function.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Взгляните:
@@ -88,7 +92,11 @@ alert(typeof User); // function
1. Создаёт функцию с именем `User`, которая становится результатом объявления класса. Код функции берётся из метода `constructor` (она будет пустой, если такого метода нет).
2. Сохраняет все методы, такие как `sayHi`, в `User.prototype`.
+<<<<<<< HEAD
При вызове метода объекта `new User` он будет взят из прототипа, как описано в главе . Таким образом, объекты `new User` имеют доступ к методам класса.
+=======
+After `new User` object is created, when we call its method, it's taken from the prototype, just as described in the chapter . So the object has access to class methods.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
На картинке показан результат объявления `class User`:
@@ -115,9 +123,15 @@ alert(User.prototype.sayHi); // alert(this.name);
alert(Object.getOwnPropertyNames(User.prototype)); // constructor, sayHi
```
+<<<<<<< HEAD
## Не просто синтаксический сахар
Иногда говорят, что `class` - это просто "синтаксический сахар" в JavaScript (синтаксис для улучшения читаемости кода, но не делающий ничего принципиально нового), потому что мы можем сделать всё то же самое без конструкции `class`:
+=======
+## Not just a syntactic sugar
+
+Sometimes people say that `class` is a "syntactic sugar" (syntax that is designed to make things easier to read, but doesn't introduce anything new), because we could actually declare the same without `class` keyword at all:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js run
// перепишем класс User на чистых функциях
@@ -126,8 +140,13 @@ alert(Object.getOwnPropertyNames(User.prototype)); // constructor, sayHi
function User(name) {
this.name = name;
}
+<<<<<<< HEAD
// каждый прототип функции имеет свойство constructor по умолчанию,
// поэтому нам нет необходимости его создавать
+=======
+// a function prototype has "constructor" property by default,
+// so we don't need to create it
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
// 2. Добавляем метод в прототип
User.prototype.sayHi = function() {
@@ -140,11 +159,21 @@ user.sayHi();
```
Результат этого кода очень похож. Поэтому, действительно, есть причины, по которым `class` можно считать синтаксическим сахаром для определения конструктора вместе с методами прототипа.
+<<<<<<< HEAD
Однако есть важные отличия:
+=======
+The result of this definition is about the same. So, there are indeed reasons why `class` can be considered a syntactic sugar to define a constructor together with its prototype methods.
+
+Still, there are important differences.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
1. Во-первых, функция, созданная с помощью `class`, помечена специальным внутренним свойством `[[FunctionKind]]:"classConstructor"`. Поэтому это не совсем то же самое, что создавать её вручную.
+<<<<<<< HEAD
В отличие от обычных функций, конструктор класса не может быть вызван без `new`:
+=======
+ The language checks for that property in a variety of places. For example, unlike a regular function, it must be called with `new`:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js run
class User {
@@ -163,6 +192,7 @@ user.sayHi();
alert(User); // class User { ... }
```
+ There are other differences, we'll see them soon.
2. Методы класса являются неперечислимыми.
Определение класса устанавливает флаг `enumerable` в` false` для всех методов в `"prototype"`.
@@ -176,7 +206,11 @@ user.sayHi();
## Class Expression
+<<<<<<< HEAD
Как и функции, классы можно определять внутри другого выражения, передавать, возвращать, присваивать и т.д.
+=======
+Just like functions, classes can be defined inside another expression, passed around, returned, assigned, etc.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Пример Class Expression (по аналогии с Function Expression):
@@ -206,7 +240,11 @@ new User().sayHi(); // работает, выводит определение M
alert(MyClass); // ошибка, имя MyClass не видно за пределами класса
```
+<<<<<<< HEAD
Мы даже можем динамически создавать классы "по запросу":
+=======
+We can even make classes dynamically "on-demand", like this:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js run
function makeClass(phrase) {
@@ -225,7 +263,11 @@ new User().sayHi(); // Привет
```
+<<<<<<< HEAD
## Геттеры/сеттеры, другие сокращения
+=======
+## Getters/setters
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Как и в литеральных объектах, в классах можно объявлять вычисляемые свойства, геттеры/сеттеры и т.д.
@@ -260,25 +302,25 @@ class User {
let user = new User("Иван");
alert(user.name); // Иван
+<<<<<<< HEAD
user = new User(""); // Имя слишком короткое.
```
При объявлении класса геттеры/сеттеры создаются на `User.prototype`, вот так:
-
-```js
-Object.defineProperties(User.prototype, {
- name: {
- get() {
- return this._name
- },
- set(name) {
- // ...
- }
- }
-});
+=======
+user = new User(""); // Name is too short.
```
+Technically, such class declaration works by creating getters and setters in `User.prototype`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
+
+## Computed names [...]
+
+<<<<<<< HEAD
Пример с вычисляемым свойством в скобках `[...]`:
+=======
+Here's an example with a computed method name using brackets `[...]`:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js run
class User {
@@ -292,17 +334,37 @@ class User {
new User().sayHi();
```
+<<<<<<< HEAD
## Свойства классов
```warn header="Старым браузерам может понадобиться полифил"
Свойства классов добавлены в язык недавно.
```
В приведённом выше примере у класса `User` были только методы. Давайте добавим свойство:
+=======
+Such features are easy to remember, as they resemble that of literal objects.
+
+## Class fields
+
+```warn header="Old browsers may need a polyfill"
+Class fields are a recent addition to the language.
+```
+
+Previously, our classes only had methods.
+
+"Class fields" is a syntax that allows to add any properties.
+
+For instance, let's add `name` property to `class User`:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js run
class User {
*!*
+<<<<<<< HEAD
name = "Аноним";
+=======
+ name = "John";
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
*/!*
sayHi() {
@@ -310,10 +372,98 @@ class User {
}
}
-new User().sayHi();
+new User().sayHi(); // Hello, John!
```
+<<<<<<< HEAD
Свойство `name` не устанавливается в `User.prototype`. Вместо этого оно создаётся оператором `new` перед запуском конструктора, это именно свойство объекта.
+=======
+So, we just write " = " in the declaration, and that's it.
+
+The important difference of class fields is that they are set on individual objects, not `User.prototype`:
+
+```js run
+class User {
+*!*
+ name = "John";
+*/!*
+}
+
+let user = new User();
+alert(user.name); // John
+alert(User.prototype.name); // undefined
+```
+
+We can also assign values using more complex expressions and function calls:
+
+```js run
+class User {
+*!*
+ name = prompt("Name, please?", "John");
+*/!*
+}
+
+let user = new User();
+alert(user.name); // John
+```
+
+
+### Making bound methods with class fields
+
+As demonstrated in the chapter functions in JavaScript have a dynamic `this`. It depends on the context of the call.
+
+So if an object method is passed around and called in another context, `this` won't be a reference to its object any more.
+
+For instance, this code will show `undefined`:
+
+```js run
+class Button {
+ constructor(value) {
+ this.value = value;
+ }
+
+ click() {
+ alert(this.value);
+ }
+}
+
+let button = new Button("hello");
+
+*!*
+setTimeout(button.click, 1000); // undefined
+*/!*
+```
+
+The problem is called "losing `this`".
+
+There are two approaches to fixing it, as discussed in the chapter :
+
+1. Pass a wrapper-function, such as `setTimeout(() => button.click(), 1000)`.
+2. Bind the method to object, e.g. in the constructor.
+
+Class fields provide another, quite elegant syntax:
+
+```js run
+class Button {
+ constructor(value) {
+ this.value = value;
+ }
+*!*
+ click = () => {
+ alert(this.value);
+ }
+*/!*
+}
+
+let button = new Button("hello");
+
+setTimeout(button.click, 1000); // hello
+```
+
+The class field `click = () => {...}` is created on a per-object basis, there's a separate function for each `Button` object, with `this` inside it referencing that object. We can pass `button.click` around anywhere, and the value of `this` will always be correct.
+
+That's especially useful in browser environment, for event listeners.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
## Итого
@@ -333,6 +483,10 @@ class MyClass {
}
```
+<<<<<<< HEAD
`MyClass` технически является функцией (той, которую мы определяем как `constructor`), в то время как методы, геттеры и сеттеры записываются в `MyClass.prototype`.
+=======
+`MyClass` is technically a function (the one that we provide as `constructor`), while methods, getters and setters are written to `MyClass.prototype`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
В следующих главах мы узнаем больше о классах, включая наследование и другие возможности.
diff --git a/1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.view/extended-clock.js b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.view/extended-clock.js
index ca613ca5e5..be2053cfcf 100644
--- a/1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.view/extended-clock.js
+++ b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.view/extended-clock.js
@@ -1,7 +1,7 @@
class ExtendedClock extends Clock {
constructor(options) {
super(options);
- let { precision=1000 } = options;
+ let { precision = 1000 } = options;
this.precision = precision;
}
diff --git a/1-js/09-classes/02-class-inheritance/article.md b/1-js/09-classes/02-class-inheritance/article.md
index b198edc00e..9a769d0e73 100644
--- a/1-js/09-classes/02-class-inheritance/article.md
+++ b/1-js/09-classes/02-class-inheritance/article.md
@@ -1,8 +1,18 @@
# Наследование классов
+<<<<<<< HEAD
Допустим, у нас есть два класса.
+=======
+# Class inheritance
-`Animal`:
+Class inheritance is a way for one class to extend another class.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
+
+So we can create new functionality on top of the existing.
+
+## The "extends" keyword
+
+Let's say we have class `Animal`:
```js
class Animal {
@@ -12,7 +22,11 @@ class Animal {
}
run(speed) {
this.speed = speed;
+<<<<<<< HEAD
alert(`${this.name} бежит со скоростью ${this.speed}.`);
+=======
+ alert(`${this.name} runs with speed ${this.speed}.`);
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
}
stop() {
this.speed = 0;
@@ -23,6 +37,7 @@ class Animal {
let animal = new Animal("Мой питомец");
```
+<<<<<<< HEAD

...И `Rabbit`:
@@ -67,6 +82,21 @@ class Animal {
}
// Наследуем от Animal указывая "extends Animal"
+=======
+Here's how we can represent `animal` object and `Animal` class graphically:
+
+
+
+...And we would like to create another `class Rabbit`.
+
+As rabbits are animals, `Rabbit` class should be based on `Animal`, have access to animal methods, so that rabbits can do what "generic" animals can do.
+
+The syntax to extend another class is: `class Child extends Parent`.
+
+Let's create `class Rabbit` that inherits from `Animal`:
+
+```js
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
*!*
class Rabbit extends Animal {
*/!*
@@ -82,6 +112,7 @@ rabbit.hide(); // Белый кролик прячется!
```
Теперь код `Rabbit` стал короче, так как используется конструктор класса `Animal` по умолчанию и кролик может использовать метод `run` как и все животные.
+<<<<<<< HEAD
Ключевое слово `extends` работает, используя прототипы. Оно устанавливает `Rabbit.prototype.[[Prototype]]` в `Animal.prototype`. Так что если метод не найден в `Rabbit.prototype`, JavaScript берёт его из `Animal.prototype`.

@@ -90,6 +121,20 @@ rabbit.hide(); // Белый кролик прячется!
````smart header="После `extends` разрешены любые выражения"
Синтаксис создания класса допускает указывать после `extends` не только класс, но любое выражение.
+=======
+Object of `Rabbit` class have access to both `Rabbit` methods, such as `rabbit.hide()`, and also to `Animal` methods, such as `rabbit.run()`.
+
+Internally, `extends` keyword works using the good old prototype mechanics. It sets `Rabbit.prototype.[[Prototype]]` to `Animal.prototype`. So, if a method is not found in `Rabbit.prototype`, JavaScript takes it from `Animal.prototype`.
+
+
+
+For instance, to find `rabbit.run` method, the engine checks (bottom-up on the picture):
+1. The `rabbit` object (has no `run`).
+2. Its prototype, that is `Rabbit.prototype` (has `hide`, but not `run`).
+3. Its prototype, that is (due to `extends`) `Animal.prototype`, that finally has the `run` method.
+
+As we can recall from the chapter , JavaScript itself uses prototypal inheritance for built-in objects. E.g. `Date.prototype.[[Prototype]]` is `Object.prototype`. That's why dates have access to generic object methods.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Пример вызова функции, которая генерирует родительский класс:
@@ -113,19 +158,36 @@ new User().sayHi(); // Привет
## Переопределение методов
+<<<<<<< HEAD
Давайте пойдём дальше и переопределим метод. Сейчас `Rabbit` наследует от `Animal` метод `stop`, который устанавливает `this.speed = 0`.
Если мы определим свой метод `stop` в классе `Rabbit`, то он будет использоваться взамен родительского:
+=======
+Now let's move forward and override a method. By default, all methods that are not specified in `class Rabbit` are taken directly "as is" from `class Animal`.
+
+But if we specify our own method in `Rabbit`, such as `stop()` then it will be used instead:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js
class Rabbit extends Animal {
stop() {
+<<<<<<< HEAD
// ...будет использован для rabbit.stop()
+=======
+ // ...now this will be used for rabbit.stop()
+ // instead of stop() from class Animal
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
}
}
```
+<<<<<<< HEAD
...Впрочем, обычно мы не хотим полностью заменить родительский метод, а скорее хотим сделать новый на его основе, изменяя или расширяя его функциональность. Мы делаем что-то в нашем методе и вызываем родительский метод до/после или в процессе.
+=======
+Usually we don't want to totally replace a parent method, but rather to build on top of it to tweak or extend its functionality. We do something in our method, but call the parent method before/after it or in the process.
+
+Classes provide `"super"` keyword for that.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
У классов есть ключевое слово `"super"` для таких случаев.
- `super.method(...)` вызывает родительский метод.
@@ -143,7 +205,11 @@ class Animal {
run(speed) {
this.speed = speed;
+<<<<<<< HEAD
alert(`${this.name} бежит со скоростью ${this.speed}.`);
+=======
+ alert(`${this.name} runs with speed ${this.speed}.`);
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
}
stop() {
@@ -198,7 +264,11 @@ setTimeout(function() { super.stop() }, 1000);
С конструкторами немного сложнее.
+<<<<<<< HEAD
До сих пор у `Rabbit` не было своего конструктора.
+=======
+Until now, `Rabbit` did not have its own `constructor`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Согласно [спецификации](https://tc39.github.io/ecma262/#sec-runtime-semantics-classdefinitionevaluation), если класс расширяет другой класс и не имеет конструктора, то автоматически создаётся такой "пустой" конструктор:
@@ -247,12 +317,19 @@ let rabbit = new Rabbit("Белый кролик", 10); // Error: this is not de
Упс! При создании кролика - ошибка! Что не так?
+<<<<<<< HEAD
Если коротко, то в классах-потомках конструктор обязан вызывать `super(...)`, и (!) делать это перед использованием `this`.
+=======
+The short answer is:
+
+- **Constructors in inheriting classes must call `super(...)`, and (!) do it before using `this`.**
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
...Но почему? Что происходит? Это требование кажется довольно странным.
Конечно, всему есть объяснение. Давайте углубимся в детали, чтобы вы действительно поняли, что происходит.
+<<<<<<< HEAD
В JavaScript существует различие между "функцией-конструктором наследующего класса" и всеми остальными. В наследующем классе соответствующая функция-конструктор помечена специальным внутренним свойством `[[ConstructorKind]]:"derived"`.
Разница в следующем:
@@ -263,6 +340,18 @@ let rabbit = new Rabbit("Белый кролик", 10); // Error: this is not de
Поэтому, если мы создаём собственный конструктор, мы должны вызвать `super`, в противном случае объект для `this` не будет создан, и мы получим ошибку.
Чтобы конструктор `Rabbit` работал, он должен вызвать `super()` до того, как использовать `this`, чтобы не было ошибки:
+=======
+In JavaScript, there's a distinction between a constructor function of an inheriting class (so-called "derived constructor") and other functions. A derived constructor has a special internal property `[[ConstructorKind]]:"derived"`. That's a special internal label.
+
+That label affects its behavior with `new`.
+
+- When a regular function is executed with `new`, it creates an empty object and assigns it to `this`.
+- But when a derived constructor runs, it doesn't do this. It expects the parent constructor to do this job.
+
+So a derived constructor must call `super` in order to execute its parent (base) constructor, otherwise the object for `this` won't be created. And we'll get an error.
+
+For the `Rabbit` constructor to work, it needs to call `super()` before using `this`, like here:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js run
class Animal {
@@ -297,8 +386,108 @@ alert(rabbit.earLength); // 10
## Устройство super, [[HomeObject]]
+<<<<<<< HEAD
```warn header="Продвинутая информация"
Если вы читаете учебник первый раз - эту секцию можно пропустить.
+=======
+
+### Overriding class fields: a tricky note
+
+```warn header="Advanced note"
+This note assumes you have a certain experience with classes, maybe in other programming languages.
+
+It provides better insight into the language and also explains the behavior that might be a source of bugs (but not very often).
+
+If you find it difficult to understand, just go on, continue reading, then return to it some time later.
+```
+
+We can override not only methods, but also class fields.
+
+Although, there's a tricky behavior when we access an overridden field in parent constructor, quite different from most other programming languages.
+
+Consider this example:
+
+```js run
+class Animal {
+ name = 'animal'
+
+ constructor() {
+ alert(this.name); // (*)
+ }
+}
+
+class Rabbit extends Animal {
+ name = 'rabbit';
+}
+
+new Animal(); // animal
+*!*
+new Rabbit(); // animal
+*/!*
+```
+
+Here, class `Rabbit` extends `Animal` and overrides `name` field with its own value.
+
+There's no own constructor in `Rabbit`, so `Animal` constructor is called.
+
+What's interesting is that in both cases: `new Animal()` and `new Rabbit()`, the `alert` in the line `(*)` shows `animal`.
+
+**In other words, parent constructor always uses its own field value, not the overridden one.**
+
+What's odd about it?
+
+If it's not clear yet, please compare with methods.
+
+Here's the same code, but instead of `this.name` field we call `this.showName()` method:
+
+```js run
+class Animal {
+ showName() { // instead of this.name = 'animal'
+ alert('animal');
+ }
+
+ constructor() {
+ this.showName(); // instead of alert(this.name);
+ }
+}
+
+class Rabbit extends Animal {
+ showName() {
+ alert('rabbit');
+ }
+}
+
+new Animal(); // animal
+*!*
+new Rabbit(); // rabbit
+*/!*
+```
+
+Please note: now the output is different.
+
+And that's what we naturally expect. When the parent constructor is called in the derived class, it uses the overridden method.
+
+...But for class fields it's not so. As said, the parent constructor always uses the parent field.
+
+Why is there the difference?
+
+Well, the reason is in the field initialization order. The class field is initialized:
+- Before constructor for the base class (that doesn't extend anything),
+- Imediately after `super()` for the derived class.
+
+In our case, `Rabbit` is the derived class. There's no `constructor()` in it. As said previously, that's the same as if there was an empty constructor with only `super(...args)`.
+
+So, `new Rabbit()` calls `super()`, thus executing the parent constructor, and (per the rule for derived classes) only after that its class fields are initialized. At the time of the parent constructor execution, there are no `Rabbit` class fields yet, that's why `Animal` fields are used.
+
+This subtle difference between fields and methods is specific to JavaScript
+
+Luckily, this behavior only reveals itself if an overridden field is used in the parent constructor. Then it may be difficult to understand what's going on, so we're explaining it here.
+
+If it becomes a problem, one can fix it by using methods or getters/setters instead of fields.
+
+
+## Super: internals, [[HomeObject]]
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Она рассказывает о внутреннем устройстве наследования и вызов `super`.
```
@@ -454,7 +643,11 @@ longEar.eat(); // Длинноух ест.
До этого мы неоднократно видели, что функции в JavaScript "свободны", не привязаны к объектам. Их можно копировать между объектами и вызывать с любым `this`.
+<<<<<<< HEAD
Но само существование `[[HomeObject]]` нарушает этот принцип, так как методы запоминают свои объекты. `[[HomeObject]]` нельзя изменить, эта связь - навсегда.
+=======
+The very existence of `[[HomeObject]]` violates that principle, because methods remember their objects. `[[HomeObject]]` can't be changed, so this bond is forever.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Единственное место в языке, где используется `[[HomeObject]]` - это `super`. Поэтому если метод не использует `super`, то мы все ещё можем считать его свободным и копировать между объектами. А вот если `super` в коде есть, то возможны побочные эффекты.
@@ -494,7 +687,11 @@ tree.sayHi(); // Я животное (?!?)
*/!*
```
+<<<<<<< HEAD
Вызов `tree.sayHi()` показывает "Я животное". Определённо неверно.
+=======
+A call to `tree.sayHi()` shows "I'm an animal". Definitely wrong.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Причина проста:
- В строке `(*)`, метод `tree.sayHi` скопирован из `rabbit`. Возможно, мы хотели избежать дублирования кода?
@@ -516,7 +713,11 @@ tree.sayHi(); // Я животное (?!?)
```js run
let animal = {
+<<<<<<< HEAD
eat: function() { // намеренно пишем так, а не eat() { ...
+=======
+ eat: function() { // intentionally writing like this instead of eat() {...
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
// ...
}
};
@@ -546,5 +747,10 @@ rabbit.eat(); // Ошибка вызова super (потому что нет [[
- Методы запоминают свой объект во внутреннем свойстве `[[HomeObject]]`. Благодаря этому работает `super`, он в его прототипе ищет родительские методы.
- Поэтому копировать метод, использующий `super`, между разными объектами небезопасно.
+<<<<<<< HEAD
Также:
- У функций-стрелок нет своего `this` и `super`, поэтому они "прозрачно" встраиваются во внешний контекст.
+=======
+Also:
+- Arrow functions don't have their own `this` or `super`, so they transparently fit into the surrounding context.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
diff --git a/1-js/09-classes/03-static-properties-methods/3-class-extend-object/rabbit-extends-object.svg b/1-js/09-classes/03-static-properties-methods/3-class-extend-object/rabbit-extends-object.svg
new file mode 100644
index 0000000000..34d783b4de
--- /dev/null
+++ b/1-js/09-classes/03-static-properties-methods/3-class-extend-object/rabbit-extends-object.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/09-classes/03-static-properties-methods/3-class-extend-object/solution.md b/1-js/09-classes/03-static-properties-methods/3-class-extend-object/solution.md
new file mode 100644
index 0000000000..ca9e80601b
--- /dev/null
+++ b/1-js/09-classes/03-static-properties-methods/3-class-extend-object/solution.md
@@ -0,0 +1,81 @@
+First, let's see why the latter code doesn't work.
+
+The reason becomes obvious if we try to run it. An inheriting class constructor must call `super()`. Otherwise `"this"` won't be "defined".
+
+So here's the fix:
+
+```js run
+class Rabbit extends Object {
+ constructor(name) {
+*!*
+ super(); // need to call the parent constructor when inheriting
+*/!*
+ this.name = name;
+ }
+}
+
+let rabbit = new Rabbit("Rab");
+
+alert( rabbit.hasOwnProperty('name') ); // true
+```
+
+But that's not all yet.
+
+Even after the fix, there's still important difference in `"class Rabbit extends Object"` versus `class Rabbit`.
+
+As we know, the "extends" syntax sets up two prototypes:
+
+1. Between `"prototype"` of the constructor functions (for methods).
+2. Between the constructor functions themselves (for static methods).
+
+In our case, for `class Rabbit extends Object` it means:
+
+```js run
+class Rabbit extends Object {}
+
+alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) true
+alert( Rabbit.__proto__ === Object ); // (2) true
+```
+
+So `Rabbit` now provides access to static methods of `Object` via `Rabbit`, like this:
+
+```js run
+class Rabbit extends Object {}
+
+*!*
+// normally we call Object.getOwnPropertyNames
+alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // a,b
+*/!*
+```
+
+But if we don't have `extends Object`, then `Rabbit.__proto__` is not set to `Object`.
+
+Here's the demo:
+
+```js run
+class Rabbit {}
+
+alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) true
+alert( Rabbit.__proto__ === Object ); // (2) false (!)
+alert( Rabbit.__proto__ === Function.prototype ); // as any function by default
+
+*!*
+// error, no such function in Rabbit
+alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // Error
+*/!*
+```
+
+So `Rabbit` doesn't provide access to static methods of `Object` in that case.
+
+By the way, `Function.prototype` has "generic" function methods, like `call`, `bind` etc. They are ultimately available in both cases, because for the built-in `Object` constructor, `Object.__proto__ === Function.prototype`.
+
+Here's the picture:
+
+
+
+So, to put it short, there are two differences:
+
+| class Rabbit | class Rabbit extends Object |
+|--------------|------------------------------|
+| -- | needs to call `super()` in constructor |
+| `Rabbit.__proto__ === Function.prototype` | `Rabbit.__proto__ === Object` |
diff --git a/1-js/09-classes/03-static-properties-methods/3-class-extend-object/task.md b/1-js/09-classes/03-static-properties-methods/3-class-extend-object/task.md
new file mode 100644
index 0000000000..1d0f98a74e
--- /dev/null
+++ b/1-js/09-classes/03-static-properties-methods/3-class-extend-object/task.md
@@ -0,0 +1,42 @@
+importance: 3
+
+---
+
+# Class extends Object?
+
+As we know, all objects normally inherit from `Object.prototype` and get access to "generic" object methods like `hasOwnProperty` etc.
+
+For instance:
+
+```js run
+class Rabbit {
+ constructor(name) {
+ this.name = name;
+ }
+}
+
+let rabbit = new Rabbit("Rab");
+
+*!*
+// hasOwnProperty method is from Object.prototype
+alert( rabbit.hasOwnProperty('name') ); // true
+*/!*
+```
+
+But if we spell it out explicitly like `"class Rabbit extends Object"`, then the result would be different from a simple `"class Rabbit"`?
+
+What's the difference?
+
+Here's an example of such code (it doesn't work -- why? fix it?):
+
+```js
+class Rabbit extends Object {
+ constructor(name) {
+ this.name = name;
+ }
+}
+
+let rabbit = new Rabbit("Rab");
+
+alert( rabbit.hasOwnProperty('name') ); // Error
+```
diff --git a/1-js/09-classes/03-static-properties-methods/article.md b/1-js/09-classes/03-static-properties-methods/article.md
index 56b26311f4..eca346795b 100644
--- a/1-js/09-classes/03-static-properties-methods/article.md
+++ b/1-js/09-classes/03-static-properties-methods/article.md
@@ -19,12 +19,18 @@ User.staticMethod(); // true
Это фактически то же самое, что присвоить метод напрямую как свойство функции:
+<<<<<<< HEAD
```js
+=======
+```js run
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
class User { }
User.staticMethod = function() {
alert(this === User);
};
+
+User.staticMethod(); // true
```
Значением `this` при вызове `User.staticMethod()` является сам конструктор класса `User` (правило "объект до точки").
@@ -123,14 +129,23 @@ alert( Article.publisher ); // Илья Кантор
Article.publisher = "Илья Кантор";
```
+<<<<<<< HEAD
## Наследование статических свойств и методов
Статические свойства и методы наследуются.
Например, метод `Animal.compare` в коде ниже наследуется и доступен как `Rabbit.compare`:
+=======
+## Inheritance of static properties and methods
+
+Static properties and methods are inherited.
+
+For instance, `Animal.compare` and `Animal.planet` in the code below are inherited and accessible as `Rabbit.compare` and `Rabbit.planet`:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js run
class Animal {
+ static planet = "Earth";
constructor(name, speed) {
this.speed = speed;
@@ -166,10 +181,19 @@ let rabbits = [
rabbits.sort(Rabbit.compare);
*/!*
+<<<<<<< HEAD
rabbits[0].run(); // Чёрный кролик бежит со скоростью 5.
```
Мы можем вызвать `Rabbit.compare`, при этом будет вызван унаследованный `Animal.compare`.
+=======
+rabbits[0].run(); // Black Rabbit runs with speed 5.
+
+alert(Rabbit.planet); // Earth
+```
+
+Now when we call `Rabbit.compare`, the inherited `Animal.compare` will be called.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Как это работает? Снова с использованием прототипов. Как вы уже могли предположить, `extends` даёт `Rabbit` ссылку `[[Prototype]]` на `Animal`.
@@ -180,7 +204,11 @@ rabbits[0].run(); // Чёрный кролик бежит со скорость
1. Функция `Rabbit` прототипно наследует от функции `Animal`.
2. `Rabbit.prototype` прототипно наследует от `Animal.prototype`.
+<<<<<<< HEAD
В результате наследование работает как для обычных, так и для статических методов.
+=======
+As a result, inheritance works both for regular and static methods.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Давайте это проверим кодом:
@@ -191,13 +219,21 @@ class Rabbit extends Animal {}
// для статики
alert(Rabbit.__proto__ === Animal); // true
+<<<<<<< HEAD
// для обычных методов
+=======
+// for regular methods
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
alert(Rabbit.prototype.__proto__ === Animal.prototype); // true
```
## Итого
+<<<<<<< HEAD
Статические методы используются для функциональности, принадлежат классу "в целом", а не относятся к конкретному объекту класса.
+=======
+Static methods are used for the functionality that belongs to the class "as a whole". It doesn't relate to a concrete class instance.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Например, метод для сравнения двух статей `Article.compare(article1, article2)` или фабричный метод `Article.createTodays()`.
diff --git a/1-js/09-classes/04-private-protected-properties-methods/article.md b/1-js/09-classes/04-private-protected-properties-methods/article.md
index 03202d77af..c3ca142061 100644
--- a/1-js/09-classes/04-private-protected-properties-methods/article.md
+++ b/1-js/09-classes/04-private-protected-properties-methods/article.md
@@ -50,8 +50,13 @@
В JavaScript есть два типа полей (свойств и методов) объекта:
+<<<<<<< HEAD
- Публичные: доступны отовсюду. Они составляют внешний интерфейс. До этого момента мы использовали только публичные свойства и методы.
- Приватные: доступны только внутри класса. Они для внутреннего интерфейса.
+=======
+- Public: accessible from anywhere. They comprise the external interface. Until now we were only using public properties and methods.
+- Private: accessible only from inside the class. These are for the internal interface.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Во многих других языках также существуют "защищённые" поля, доступные только внутри класса или для дочерних классов (то есть, как приватные, но разрешён доступ для наследующих классов) и также полезны для внутреннего интерфейса. В некотором смысле они более распространены, чем приватные, потому что мы обычно хотим, чтобы наследующие классы получали доступ к внутренним полям.
@@ -255,7 +260,11 @@ class MegaCoffeeMachine extends CoffeeMachine {
}
```
+<<<<<<< HEAD
Во многих случаях такое ограничение слишком жёсткое. Раз уж мы расширяем `CoffeeMachine`, у нас может быть вполне законная причина для доступа к внутренним методам и свойствам. Поэтому защищённые свойства используются чаще, хоть они и не поддерживаются синтаксисом языка.
+=======
+In many scenarios such limitation is too severe. If we extend a `CoffeeMachine`, we may have legitimate reasons to access its internals. That's why protected fields are used more often, even though they are not supported by the language syntax.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
````warn
Приватные поля особенные.
@@ -276,12 +285,21 @@ class User {
## Итого
+<<<<<<< HEAD
В терминах ООП отделение внутреннего интерфейса от внешнего называется [инкапсуляция](https://ru.wikipedia.org/wiki/%D0%98%D0%BD%D0%BA%D0%B0%D0%BF%D1%81%D1%83%D0%BB%D1%8F%D1%86%D0%B8%D1%8F_(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)).
+=======
+In terms of OOP, delimiting of the internal interface from the external one is called [encapsulation](https://en.wikipedia.org/wiki/Encapsulation_(computer_programming)).
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Это даёт следующие выгоды:
+<<<<<<< HEAD
Защита для пользователей, чтобы они не выстрелили себе в ногу
: Представьте себе, что есть команда разработчиков, использующая кофеварку. Она была изготовлена компанией "Лучшие Кофеварки" и работает нормально, но защитный кожух был снят. Внутренний интерфейс стал доступен извне.
+=======
+Protection for users, so that they don't shoot themselves in the foot
+: Imagine, there's a team of developers using a coffee machine. It was made by the "Best CoffeeMachine" company, and works fine, but a protective cover was removed. So the internal interface is exposed.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Все разработчики культурны -- они используют кофеварку по назначению. Но один из них, Джон, решил, что он самый умный, и сделал некоторые изменения во внутренностях кофеварки. После чего кофеварка вышла из строя через два дня.
@@ -305,9 +323,16 @@ class User {
**Всегда удобно, когда детали реализации скрыты, и доступен простой, хорошо документированный внешний интерфейс.**
+<<<<<<< HEAD
Для сокрытия внутреннего интерфейса мы используем защищённые или приватные свойства:
- Защищённые поля имеют префикс `_`. Это хорошо известное соглашение, не поддерживаемое на уровне языка. Программисты должны обращаться к полю, начинающемуся с `_`, только из его класса и классов, унаследованных от него.
- Приватные поля имеют префикс `#`. JavaScript гарантирует, что мы можем получить доступ к таким полям только внутри класса.
+=======
+To hide an internal interface we use either protected or private properties:
+
+- Protected fields start with `_`. That's a well-known convention, not enforced at the language level. Programmers should only access a field starting with `_` from its class and classes inheriting from it.
+- Private fields start with `#`. JavaScript makes sure we can only access those from inside the class.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
В настоящее время приватные поля не очень хорошо поддерживаются в браузерах, но можно использовать полифил.
diff --git a/1-js/09-classes/05-extend-natives/article.md b/1-js/09-classes/05-extend-natives/article.md
index 41ba26ee95..b77f468e2c 100644
--- a/1-js/09-classes/05-extend-natives/article.md
+++ b/1-js/09-classes/05-extend-natives/article.md
@@ -21,7 +21,11 @@ alert(filteredArr); // 10, 50
alert(filteredArr.isEmpty()); // false
```
+<<<<<<< HEAD
Обратите внимание на интересный момент: встроенные методы, такие как `filter`, `map` и другие возвращают новые объекты унаследованного класса `PowerArray`. Их внутренняя реализация такова, что для этого они используют свойство объекта `constructor`.
+=======
+Please note a very interesting thing. Built-in methods like `filter`, `map` and others -- return new objects of exactly the inherited type `PowerArray`. Their internal implementation uses the object's `constructor` property for that.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
В примере выше,
```js
@@ -32,7 +36,11 @@ arr.constructor === PowerArray
Более того, мы можем настроить это поведение.
+<<<<<<< HEAD
При помощи специального статического геттера `Symbol.species` можно вернуть конструктор, который JavaScript будет использовать в `filter`, `map` и других методах для создания новых объектов.
+=======
+We can add a special static getter `Symbol.species` to the class. If it exists, it should return the constructor that JavaScript will use internally to create new entities in `map`, `filter` and so on.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Если бы мы хотели, чтобы методы `map`, `filter` и т. д. возвращали обычные массивы, мы могли бы вернуть `Array` в `Symbol.species`, вот так:
@@ -74,11 +82,19 @@ alert(filteredArr.isEmpty()); // Error: filteredArr.isEmpty is not a function
Как мы уже знаем, встроенные классы расширяют друг друга.
+<<<<<<< HEAD
Обычно, когда один класс наследует другому, то наследуются и статические методы. Это было подробно разъяснено в главе [](info:static-properties-methods#statics-and-inheritance).
+=======
+Normally, when one class extends another, both static and non-static methods are inherited. That was thoroughly explained in the article [](info:static-properties-methods#statics-and-inheritance).
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Но встроенные классы - исключение. Они не наследуют статические методы друг друга.
+<<<<<<< HEAD
Например, и `Array`, и `Date` наследуют от `Object`, так что в их экземплярах доступны методы из `Object.prototype`. Но `Array.[[Prototype]]` не ссылается на `Object`, поэтому нет методов `Array.keys()` или `Date.keys()`.
+=======
+For example, both `Array` and `Date` inherit from `Object`, so their instances have methods from `Object.prototype`. But `Array.[[Prototype]]` does not reference `Object`, so there's no, for instance, `Array.keys()` (or `Date.keys()`) static method.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Ниже вы видите структуру `Date` и `Object`:
diff --git a/1-js/09-classes/06-instanceof/1-strange-instanceof/task.md b/1-js/09-classes/06-instanceof/1-strange-instanceof/task.md
index fcfce37f74..c332c5a20f 100644
--- a/1-js/09-classes/06-instanceof/1-strange-instanceof/task.md
+++ b/1-js/09-classes/06-instanceof/1-strange-instanceof/task.md
@@ -4,7 +4,11 @@ importance: 5
# Странный instanceof
+<<<<<<< HEAD
Почему `instanceof` в примере ниже возвращает `true`? Мы же видим, что `a` не создан с помощью `B()`.
+=======
+In the code below, why does `instanceof` return `true`? We can easily see that `a` is not created by `B()`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js run
function A() {}
diff --git a/1-js/09-classes/06-instanceof/article.md b/1-js/09-classes/06-instanceof/article.md
index 833c59d4ab..96003c1efe 100644
--- a/1-js/09-classes/06-instanceof/article.md
+++ b/1-js/09-classes/06-instanceof/article.md
@@ -2,7 +2,11 @@
Оператор `instanceof` позволяет проверить, к какому классу принадлежит объект, с учётом наследования.
+<<<<<<< HEAD
Такая проверка может потребоваться во многих случаях. Здесь мы используем её для создания *полиморфной* функции, которая интерпретирует аргументы по-разному в зависимости от их типа.
+=======
+Such a check may be necessary in many cases. Here we'll use it for building a *polymorphic* function, the one that treats arguments differently depending on their type.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
## Оператор instanceof [#ref-instanceof]
@@ -46,7 +50,11 @@ alert( arr instanceof Object ); // true
Пожалуйста, обратите внимание, что `arr` также принадлежит классу `Object`, потому что `Array` наследует от `Object`.
+<<<<<<< HEAD
Обычно оператор `instanceof` просматривает для проверки цепочку прототипов. Но это поведение может быть изменено при помощи статического метода `Symbol.hasInstance`.
+=======
+Normally, `instanceof` examines the prototype chain for the check. We can also set a custom logic in the static method `Symbol.hasInstance`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Алгоритм работы `obj instanceof Class` работает примерно так:
@@ -67,7 +75,11 @@ alert( arr instanceof Object ); // true
alert(obj instanceof Animal); // true: вызван Animal[Symbol.hasInstance](obj)
```
+<<<<<<< HEAD
2. Большая часть классов не имеет метода `Symbol.hasInstance`. В этом случае используется стандартная логика: проверяется, равен ли `Class.prototype` одному из прототипов в прототипной цепочке `obj`.
+=======
+2. Most classes do not have `Symbol.hasInstance`. In that case, the standard logic is used: `obj instanceOf Class` checks whether `Class.prototype` is equal to one of the prototypes in the `obj` prototype chain.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Другими словами, сравнивается:
```js
@@ -104,9 +116,15 @@ alert( arr instanceof Object ); // true
Кстати, есть метод [objA.isPrototypeOf(objB)](mdn:js/object/isPrototypeOf), который возвращает `true`, если объект `objA` есть где-то в прототипной цепочке объекта `objB`. Так что `obj instanceof Class` можно перефразировать как `Class.prototype.isPrototypeOf(obj)`.
+<<<<<<< HEAD
Забавно, но сам конструктор `Class` не участвует в процессе проверки! Важна только цепочка прототипов `Class.prototype`.
Это может приводить к интересным последствиям при изменении свойства `prototype` после создания объекта.
+=======
+It's funny, but the `Class` constructor itself does not participate in the check! Only the chain of prototypes and `Class.prototype` matters.
+
+That can lead to interesting consequences when a `prototype` property is changed after the object is created.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Как, например, тут:
@@ -185,11 +203,19 @@ let user = {
alert( {}.toString.call(user) ); // [object User]
```
+<<<<<<< HEAD
Такое свойство есть у большей части объектов, специфичных для определённых окружений. Вот несколько примеров для браузера:
```js run
// toStringTag для браузерного объекта и класса
alert( window[Symbol.toStringTag]); // window
+=======
+For most environment-specific objects, there is such a property. Here are some browser specific examples:
+
+```js run
+// toStringTag for the environment-specific object and class:
+alert( window[Symbol.toStringTag]); // Window
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
alert( XMLHttpRequest.prototype[Symbol.toStringTag] ); // XMLHttpRequest
alert( {}.toString.call(window) ); // [object Window]
diff --git a/1-js/09-classes/07-mixins/article.md b/1-js/09-classes/07-mixins/article.md
index f5afa3ee14..c73b321513 100644
--- a/1-js/09-classes/07-mixins/article.md
+++ b/1-js/09-classes/07-mixins/article.md
@@ -101,7 +101,11 @@ new User("Вася").sayHi(); // Привет, Вася!

+<<<<<<< HEAD
Это связано с тем, что методы `sayHi` и `sayBye` были изначально созданы в объекте `sayHiMixin`. Несмотря на то, что они скопированы, их внутреннее свойство `[[HomeObject]]` ссылается на `sayHiMixin`, как показано на картинке выше.
+=======
+That's because methods `sayHi` and `sayBye` were initially created in `sayHiMixin`. So even though they got copied, their `[[HomeObject]]` internal property references `sayHiMixin`, as shown in the picture above.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Так как `super` ищет родительские методы в `[[HomeObject]].[[Prototype]]`, это означает `sayHiMixin.[[Prototype]]`, а не `User.[[Prototype]]`.
@@ -109,6 +113,7 @@ new User("Вася").sayHi(); // Привет, Вася!
Многие объекты в браузерной разработке (и не только) обладают важной способностью - они могут генерировать события. События - отличный способ передачи информации всем, кто в ней заинтересован. Давайте создадим примесь, которая позволит легко добавлять функциональность по работе с событиями любым классам/объектам.
+<<<<<<< HEAD
- Примесь добавит метод `.trigger(name, [data])` для генерации события. Аргумент `name` - это имя события, за которым могут следовать другие аргументы с данными для события.
- Также будет добавлен метод `.on(name, handler)`, который назначает обработчик для события с заданным именем. Обработчик будет вызван, когда произойдёт событие с указанным именем `name`, и получит данные из `.trigger`.
- ...и метод `.off(name, handler)`, который удаляет обработчик указанного события.
@@ -116,6 +121,15 @@ new User("Вася").sayHi(); // Привет, Вася!
После того, как все методы примеси будут добавлены, объект `user` сможет сгенерировать событие `"login"` после входа пользователя в личный кабинет. А другой объект, к примеру, `calendar` сможет использовать это событие, чтобы показывать зашедшему пользователю актуальный для него календарь.
Или `menu` может генерировать событие `"select"`, когда элемент меню выбран, а другие объекты могут назначать обработчики, чтобы реагировать на это событие, и т.п.
+=======
+An important feature of many browser objects (for instance) is that they can generate events. Events are a great way to "broadcast information" to anyone who wants it. So let's make a mixin that allows us to easily add event-related functions to any class/object.
+
+- The mixin will provide a method `.trigger(name, [...data])` to "generate an event" when something important happens to it. The `name` argument is a name of the event, optionally followed by additional arguments with event data.
+- Also the method `.on(name, handler)` that adds `handler` function as the listener to events with the given name. It will be called when an event with the given `name` triggers, and get the arguments from the `.trigger` call.
+- ...And the method `.off(name, handler)` that removes the `handler` listener.
+
+After adding the mixin, an object `user` will be able to generate an event `"login"` when the visitor logs in. And another object, say, `calendar` may want to listen for such events to load the calendar for the logged-in person.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Вот код примеси:
@@ -138,7 +152,7 @@ let eventMixin = {
* menu.off('select', handler)
*/
off(eventName, handler) {
- let handlers = this._eventHandlers && this._eventHandlers[eventName];
+ let handlers = this._eventHandlers?.[eventName];
if (!handlers) return;
for (let i = 0; i < handlers.length; i++) {
if (handlers[i] === handler) {
@@ -152,8 +166,13 @@ let eventMixin = {
* this.trigger('select', data1, data2);
*/
trigger(eventName, ...args) {
+<<<<<<< HEAD
if (!this._eventHandlers || !this._eventHandlers[eventName]) {
return; // обработчиков для этого события нет
+=======
+ if (!this._eventHandlers?.[eventName]) {
+ return; // no handlers for that event name
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
}
// вызовем обработчики
@@ -168,7 +187,13 @@ let eventMixin = {
2. `.off(eventName, handler)` -- убирает функцию из списка обработчиков.
+<<<<<<< HEAD
3. `.trigger(eventName, ...args)` -- генерирует событие: все назначенные обработчики из `_eventHandlers[eventName]` вызываются, и `...args` передаются им в качестве аргументов.
+=======
+- `.on(eventName, handler)` -- assigns function `handler` to run when the event with that name occurs. Technically, there's an `_eventHandlers` property that stores an array of handlers for each event name, and it just adds it to the list.
+- `.off(eventName, handler)` -- removes the function from the handlers list.
+- `.trigger(eventName, ...args)` -- generates the event: all handlers from `_eventHandlers[eventName]` are called, with a list of arguments `...args`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Использование:
@@ -193,7 +218,11 @@ menu.on("select", value => alert(`Выбранное значение: ${value}`
menu.choose("123"); // Выбранное значение: 123
```
+<<<<<<< HEAD
Теперь если у нас есть код, заинтересованный в событии `"select"`, то он может слушать его с помощью `menu.on(...)`.
+=======
+Now, if we'd like any code to react to a menu selection, we can listen for it with `menu.on(...)`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
А `eventMixin` позволяет легко добавить такое поведение в любой класс без вмешательства в цепочку наследования.
@@ -203,6 +232,12 @@ menu.choose("123"); // Выбранное значение: 123
Некоторые другие языки допускают множественное наследование. JavaScript не поддерживает множественное наследование, но с помощью примесей мы можем реализовать нечто похожее, скопировав методы в прототип.
+<<<<<<< HEAD
Мы можем использовать примеси для расширения функциональности классов, например, для обработки событий, как мы сделали это выше.
С примесями могут возникнуть конфликты, если они перезаписывают существующие методы класса. Стоит помнить об этом и быть внимательнее при выборе имён для методов примеси, чтобы их избежать.
+=======
+We can use mixins as a way to augment a class by adding multiple behaviors, like event-handling as we have seen above.
+
+Mixins may become a point of conflict if they accidentally overwrite existing class methods. So generally one should think well about the naming methods of a mixin, to minimize the probability of that happening.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
diff --git a/1-js/09-classes/07-mixins/head.html b/1-js/09-classes/07-mixins/head.html
index dfe7eda551..82854f1247 100644
--- a/1-js/09-classes/07-mixins/head.html
+++ b/1-js/09-classes/07-mixins/head.html
@@ -18,7 +18,7 @@
* menu.off('select', handler)
*/
off(eventName, handler) {
- let handlers = this._eventHandlers && this._eventHandlers[eventName];
+ let handlers = this._eventHandlers?.[eventName];
if (!handlers) return;
for(let i = 0; i < handlers.length; i++) {
if (handlers[i] == handler) {
diff --git a/1-js/10-error-handling/1-try-catch/article.md b/1-js/10-error-handling/1-try-catch/article.md
index 2b55e584ff..74d9c54019 100644
--- a/1-js/10-error-handling/1-try-catch/article.md
+++ b/1-js/10-error-handling/1-try-catch/article.md
@@ -1,10 +1,18 @@
# Обработка ошибок, "try..catch"
+<<<<<<< HEAD
Неважно, насколько мы хороши в программировании, иногда наши скрипты содержат ошибки. Они могут возникать из-за наших промахов, неожиданного ввода пользователя, неправильного ответа сервера и по тысяче других причин.
+=======
+No matter how great we are at programming, sometimes our scripts have errors. They may occur because of our mistakes, an unexpected user input, an erroneous server response, and for a thousand other reasons.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Обычно скрипт в случае ошибки "падает" (сразу же останавливается), с выводом ошибки в консоль.
+<<<<<<< HEAD
Но есть синтаксическая конструкция `try..catch`, которая позволяет "ловить" ошибки и вместо падения делать что-то более осмысленное.
+=======
+But there's a syntax construct `try..catch` that allows us to "catch" errors so the script can, instead of dying, do something more reasonable.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
## Синтаксис "try..catch"
@@ -24,6 +32,7 @@ try {
Работает она так:
+<<<<<<< HEAD
1. Сначала выполняется код внутри блока `try {...}`.
2. Если в нём нет ошибок, то блок `catch(err)` игнорируется: выполнение доходит до конца `try` и потом далее, полностью пропуская `catch`.
3. Если же в нём возникает ошибка, то выполнение `try` прерывается, и поток управления переходит в начало `catch(err)`. Переменная `err` (можно использовать любое имя) содержит объект ошибки с подробной информацией о произошедшем.
@@ -33,6 +42,17 @@ try {
Таким образом, при ошибке в блоке `try {…}` скрипт не "падает", и мы получаем возможность обработать ошибку внутри `catch`.
Давайте рассмотрим примеры.
+=======
+1. First, the code in `try {...}` is executed.
+2. If there were no errors, then `catch(err)` is ignored: the execution reaches the end of `try` and goes on, skipping `catch`.
+3. If an error occurs, then the `try` execution is stopped, and control flows to the beginning of `catch(err)`. The `err` variable (we can use any name for it) will contain an error object with details about what happened.
+
+
+
+So, an error inside the `try {…}` block does not kill the script -- we have a chance to handle it in `catch`.
+
+Let's look at some examples.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
- Пример без ошибок: выведет `alert` `(1)` и `(2)`:
@@ -87,7 +107,11 @@ try {
JavaScript-движок сначала читает код, а затем исполняет его. Ошибки, которые возникают во время фазы чтения, называются ошибками парсинга. Их нельзя обработать (изнутри этого кода), потому что движок не понимает код.
+<<<<<<< HEAD
Таким образом, `try..catch` может обрабатывать только ошибки, которые возникают в корректном коде. Такие ошибки называют "ошибками во время выполнения", а иногда "исключениями".
+=======
+So, `try..catch` can only handle errors that occur in valid code. Such errors are called "runtime errors" or, sometimes, "exceptions".
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
````
@@ -201,7 +225,11 @@ alert( user.age ); // 30
**Если `json` некорректен, `JSON.parse` генерирует ошибку, то есть скрипт "падает".**
+<<<<<<< HEAD
Устроит ли нас такое поведение? Конечно нет!
+=======
+Should we be satisfied with that? Of course not!
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Получается, что если вдруг что-то не так с данными, то посетитель никогда (если, конечно, не откроет консоль) об этом не узнает. А люди очень не любят, когда что-то "просто падает" без всякого сообщения об ошибке.
@@ -298,7 +326,7 @@ try {
*!*
alert(e.name); // SyntaxError
*/!*
- alert(e.message); // Unexpected token o in JSON at position 2
+ alert(e.message); // Unexpected token b in JSON at position 2
}
```
@@ -334,9 +362,15 @@ try {
## Проброс исключения
+<<<<<<< HEAD
В примере выше мы использовали `try..catch` для обработки некорректных данных. А что, если в блоке `try {...}` возникнет *другая неожиданная ошибка*? Например, программная (неопределённая переменная) или какая-то ещё, а не ошибка, связанная с некорректными данными.
Пример:
+=======
+In the example above we use `try..catch` to handle incorrect data. But is it possible that *another unexpected error* occurs within the `try {...}` block? Like a programming error (variable is not defined) or something else, not just this "incorrect data" thing.
+
+For example:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js run
let json = '{ "age": 30 }'; // данные неполны
@@ -353,20 +387,43 @@ try {
Конечно, возможно все! Программисты совершают ошибки. Даже в утилитах с открытым исходным кодом, используемых миллионами людей на протяжении десятилетий -- вдруг может быть обнаружена ошибка, которая приводит к ужасным взломам.
+<<<<<<< HEAD
В нашем случае `try..catch` предназначен для выявления ошибок, связанных с некорректными данными. Но по своей природе `catch` получает *все* свои ошибки из `try`. Здесь он получает неожиданную ошибку, но всё также показывает то же самое сообщение `"JSON Error"`. Это неправильно и затрудняет отладку кода.
К счастью, мы можем выяснить, какую ошибку мы получили, например, по её свойству `name`:
+=======
+In our case, `try..catch` is placed to catch "incorrect data" errors. But by its nature, `catch` gets *all* errors from `try`. Here it gets an unexpected error, but still shows the same `"JSON Error"` message. That's wrong and also makes the code more difficult to debug.
+
+To avoid such problems, we can employ the "rethrowing" technique. The rule is simple:
+
+**Catch should only process errors that it knows and "rethrow" all others.**
+
+The "rethrowing" technique can be explained in more detail as:
+
+1. Catch gets all errors.
+2. In the `catch(err) {...}` block we analyze the error object `err`.
+3. If we don't know how to handle it, we do `throw err`.
+
+Usually, we can check the error type using the `instanceof` operator:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js run
try {
user = { /*...*/ };
-} catch(e) {
+} catch(err) {
*!*
+<<<<<<< HEAD
alert(e.name); // "ReferenceError" из-за неопределённой переменной
+=======
+ if (err instanceof ReferenceError) {
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
*/!*
+ alert('ReferenceError'); // "ReferenceError" for accessing an undefined variable
+ }
}
```
+<<<<<<< HEAD
Есть простое правило:
**Блок `catch` должен обрабатывать только те ошибки, которые ему известны, и "пробрасывать" все остальные.**
@@ -376,6 +433,9 @@ try {
1. Блок `catch` получает все ошибки.
2. В блоке `catch(err) {...}` мы анализируем объект ошибки `err`.
3. Если мы не знаем как её обработать, тогда делаем `throw err`.
+=======
+We can also get the error class name from `err.name` property. All native errors have it. Another option is to read `err.constructor.name`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
В коде ниже мы используем проброс исключения, `catch` обрабатывает только `SyntaxError`:
@@ -398,7 +458,7 @@ try {
} catch(e) {
*!*
- if (e.name == "SyntaxError") {
+ if (e instanceof SyntaxError) {
alert( "JSON Error: " + e.message );
} else {
throw e; // проброс (*)
@@ -425,7 +485,7 @@ function readData() {
*/!*
} catch (e) {
// ...
- if (e.name != 'SyntaxError') {
+ if (!(e instanceof SyntaxError)) {
*!*
throw e; // проброс исключения (не знаю как это обработать)
*/!*
@@ -582,11 +642,19 @@ function func() {
Информация из данной секции не является частью языка JavaScript.
```
+<<<<<<< HEAD
Давайте представим, что произошла фатальная ошибка (программная или что-то ещё ужасное) снаружи `try..catch`, и скрипт упал.
Существует ли способ отреагировать на такие ситуации? Мы можем захотеть залогировать ошибку, показать что-то пользователю (обычно они не видят сообщение об ошибке) и т.д.
Такого способа нет в спецификации, но обычно окружения предоставляют его, потому что это весьма полезно. Например, в Node.js для этого есть [`process.on("uncaughtException")`](https://nodejs.org/api/process.html#process_event_uncaughtexception). А в браузере мы можем присвоить функцию специальному свойству [window.onerror](mdn:api/GlobalEventHandlers/onerror), которая будет вызвана в случае необработанной ошибки.
+=======
+Let's imagine we've got a fatal error outside of `try..catch`, and the script died. Like a programming error or some other terrible thing.
+
+Is there a way to react on such occurrences? We may want to log the error, show something to the user (normally they don't see error messages), etc.
+
+There is none in the specification, but environments usually provide it, because it's really useful. For instance, Node.js has [`process.on("uncaughtException")`](https://nodejs.org/api/process.html#process_event_uncaughtexception) for that. And in the browser we can assign a function to the special [window.onerror](mdn:api/GlobalEventHandlers/onerror) property, that will run in case of an uncaught error.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Синтаксис:
@@ -668,4 +736,8 @@ try {
*Проброс исключения* -- это очень важный приём обработки ошибок: блок `catch` обычно ожидает и знает, как обработать определённый тип ошибок, поэтому он должен пробрасывать дальше ошибки, о которых он не знает.
+<<<<<<< HEAD
Даже если у нас нет `try..catch`, большинство сред позволяют настроить "глобальный" обработчик ошибок, чтобы ловить ошибки, которые "выпадают наружу". В браузере это `window.onerror`.
+=======
+Even if we don't have `try..catch`, most environments allow us to setup a "global" error handler to catch errors that "fall out". In-browser, that's `window.onerror`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
diff --git a/1-js/10-error-handling/2-custom-errors/1-format-error/solution.md b/1-js/10-error-handling/2-custom-errors/1-format-error/solution.md
index e42c4e1c80..b4b8762090 100644
--- a/1-js/10-error-handling/2-custom-errors/1-format-error/solution.md
+++ b/1-js/10-error-handling/2-custom-errors/1-format-error/solution.md
@@ -2,7 +2,7 @@
class FormatError extends SyntaxError {
constructor(message) {
super(message);
- this.name = "FormatError";
+ this.name = this.constructor.name;
}
}
diff --git a/1-js/10-error-handling/2-custom-errors/article.md b/1-js/10-error-handling/2-custom-errors/article.md
index 2cbc1b2d29..7b943da980 100644
--- a/1-js/10-error-handling/2-custom-errors/article.md
+++ b/1-js/10-error-handling/2-custom-errors/article.md
@@ -2,11 +2,19 @@
Когда что-то разрабатываем, то нам часто необходимы собственные классы ошибок для разных вещей, которые могут пойти не так в наших задачах. Для ошибок при работе с сетью может понадобиться `HttpError`, для операций с базой данных `DbError`, для поиска - `NotFoundError` и т.д.
+<<<<<<< HEAD
Наши ошибки должны поддерживать базовые свойства, такие как `message`, `name` и, желательно, `stack`. Но также они могут иметь свои собственные свойства. Например, объекты `HttpError` могут иметь свойство `statusCode` со значениями `404`, `403` или `500`.
+=======
+Our errors should support basic error properties like `message`, `name` and, preferably, `stack`. But they also may have other properties of their own, e.g. `HttpError` objects may have a `statusCode` property with a value like `404` or `403` or `500`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
JavaScript позволяет вызывать `throw` с любыми аргументами, то есть технически наши классы ошибок не нуждаются в наследовании от `Error`. Но если использовать наследование, то появляется возможность идентификации объектов ошибок посредством `obj instanceof Error`. Так что лучше применять наследование.
+<<<<<<< HEAD
По мере роста приложения, наши собственные ошибки образуют иерархию, например, `HttpTimeoutError` может наследовать от ` HttpError` и так далее.
+=======
+As the application grows, our own errors naturally form a hierarchy. For instance, `HttpTimeoutError` may inherit from `HttpError`, and so on.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
## Расширение Error
@@ -23,9 +31,13 @@ let json = `{ "name": "John", "age": 30 }`;
Назовём её ошибкой валидации `ValidationError` и создадим для неё класс. Ошибка этого вида должна содержать информацию о поле, которое является источником ошибки.
+<<<<<<< HEAD
Наш класс `ValidationError` должен наследовать от встроенного класса `Error`.
Класс `Error` встроенный, вот его примерный код, просто чтобы мы понимали, что расширяем:
+=======
+That class is built-in, but here's its approximate code so we can understand what we're extending:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js
// "Псевдокод" встроенного класса Error, определённого самим JavaScript
@@ -182,7 +194,11 @@ try {
Новый класс `PropertyRequiredError` очень просто использовать: необходимо указать только имя свойства `new PropertyRequiredError(property)`. Сообщение для пользователя `message` генерируется конструктором.
+<<<<<<< HEAD
Обратите внимание, что свойство `this.name` в конструкторе `PropertyRequiredError` снова присвоено вручную. Правда, немного утомительно -- присваивать `this.name = ` в каждом классе пользовательской ошибки. Можно этого избежать, если сделать наш собственный "базовый" класс ошибки, который будет ставить `this.name = this.constructor.name`. И затем наследовать все ошибки уже от него.
+=======
+Please note that `this.name` in `PropertyRequiredError` constructor is again assigned manually. That may become a bit tedious -- to assign `this.name = ` in every custom error class. We can avoid it by making our own "basic error" class that assigns `this.name = this.constructor.name`. And then inherit all our custom errors from it.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Давайте назовём его `MyError`.
@@ -220,11 +236,47 @@ alert( new PropertyRequiredError("field").name ); // PropertyRequiredError
Код, который вызывает `readUser`, должен обрабатывать эти ошибки.
+<<<<<<< HEAD
Сейчас в нём используются проверки `if` в блоке `catch`, которые проверяют класс и обрабатывают известные ошибки и пробрасывают дальше неизвестные. Но если функция `readUser` генерирует несколько видов ошибок, то мы должны спросить себя: действительно ли мы хотим проверять все типы ошибок поодиночке во всех местах в коде, где вызывается `readUser`?
Часто ответ "Нет": внешний код хочет быть на один уровень выше всего этого. Он хочет иметь какую-то обобщённую ошибку чтения данных. Почему именно это произошло -- часто не имеет значения (об этом говорится в сообщении об ошибке). Или даже лучше, если есть способ получить подробности об ошибке, но только если нам это нужно.
Итак, давайте создадим новый класс `ReadError` для представления таких ошибок. Если ошибка возникает внутри `readUser`, мы её перехватим и сгенерируем `ReadError`. Мы также сохраним ссылку на исходную ошибку в свойстве `cause`. Тогда внешний код должен будет только проверить наличие `ReadError`.
+=======
+The code which calls `readUser` should handle these errors. Right now it uses multiple `if`s in the `catch` block, that check the class and handle known errors and rethrow the unknown ones.
+
+The scheme is like this:
+
+```js
+try {
+ ...
+ readUser() // the potential error source
+ ...
+} catch (err) {
+ if (err instanceof ValidationError) {
+ // handle validation errors
+ } else if (err instanceof SyntaxError) {
+ // handle syntax errors
+ } else {
+ throw err; // unknown error, rethrow it
+ }
+}
+```
+
+In the code above we can see two types of errors, but there can be more.
+
+If the `readUser` function generates several kinds of errors, then we should ask ourselves: do we really want to check for all error types one-by-one every time?
+
+Often the answer is "No": we'd like to be "one level above all that". We just want to know if there was a "data reading error" -- why exactly it happened is often irrelevant (the error message describes it). Or, even better, we'd like to have a way to get the error details, but only if we need to.
+
+The technique that we describe here is called "wrapping exceptions".
+
+1. We'll make a new class `ReadError` to represent a generic "data reading" error.
+2. The function `readUser` will catch data reading errors that occur inside it, such as `ValidationError` and `SyntaxError`, and generate a `ReadError` instead.
+3. The `ReadError` object will keep the reference to the original error in its `cause` property.
+
+Then the code that calls `readUser` will only have to check for `ReadError`, not for every kind of data reading errors. And if it needs more details of an error, it can check its `cause` property.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Этот код определяет ошибку `ReadError` и демонстрирует её использование в `readUser`и `try..catch`:
@@ -296,12 +348,24 @@ try {
В приведённом выше коде `readUser` работает так, как описано - функция распознаёт синтаксические ошибки и ошибки валидации и выдаёт вместо них ошибки `ReadError` (неизвестные ошибки, как обычно, пробрасываются).
+<<<<<<< HEAD
Внешний код проверяет только `instanceof ReadError`. Не нужно перечислять все возможные типы ошибок
Этот подход называется "обёртывание исключений", потому что мы берём "исключения низкого уровня" и "оборачиваем" их в `ReadError`, который является более абстрактным и более удобным для использования в вызывающем коде. Такой подход широко используется в объектно-ориентированном программировании.
+=======
+So the outer code checks `instanceof ReadError` and that's it. No need to list all possible error types.
+
+The approach is called "wrapping exceptions", because we take "low level" exceptions and "wrap" them into `ReadError` that is more abstract. It is widely used in object-oriented programming.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
## Итого
+<<<<<<< HEAD
- Мы можем наследовать свои классы ошибок от `Error` и других встроенных классов ошибок, но нужно позаботиться о свойстве `name` и не забыть вызвать `super`.
- Мы можем использовать `instanceof` для проверки типа ошибок. Это также работает с наследованием. Но иногда у нас объект ошибки, возникшей в сторонней библиотеке, и нет простого способа получить класс. Тогда для проверки типа ошибки можно использовать свойство `name`.
- Обёртывание исключений является распространённой техникой: функция ловит низкоуровневые исключения и создаёт одно "высокоуровневое" исключение вместо разных низкоуровневых. Иногда низкоуровневые исключения становятся свойствами этого объекта, как `err.cause` в примерах выше, но это не обязательно.
+=======
+- We can inherit from `Error` and other built-in error classes normally. We just need to take care of the `name` property and don't forget to call `super`.
+- We can use `instanceof` to check for particular errors. It also works with inheritance. But sometimes we have an error object coming from a 3rd-party library and there's no easy way to get its class. Then `name` property can be used for such checks.
+- Wrapping exceptions is a widespread technique: a function handles low-level exceptions and creates higher-level errors instead of various low-level ones. Low-level exceptions sometimes become properties of that object like `err.cause` in the examples above, but that's not strictly required.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
diff --git a/1-js/11-async/01-callbacks/article.md b/1-js/11-async/01-callbacks/article.md
index d11f67900f..eb460275ab 100644
--- a/1-js/11-async/01-callbacks/article.md
+++ b/1-js/11-async/01-callbacks/article.md
@@ -2,18 +2,39 @@
# Введение: колбэки
+<<<<<<< HEAD
Многие действия в JavaScript *асинхронные*.
Например, рассмотрим функцию `loadScript(src)`:
+=======
+```warn header="We use browser methods in examples here"
+To demonstrate the use of callbacks, promises and other abstract concepts, we'll be using some browser methods: specifically, loading scripts and performing simple document manipulations.
+
+If you're not familiar with these methods, and their usage in the examples is confusing, you may want to read a few chapters from the [next part](/document) of the tutorial.
+
+Although, we'll try to make things clear anyway. There won't be anything really complex browser-wise.
+```
+
+Many functions are provided by JavaScript host environments that allow you to schedule *asynchronous* actions. In other words, actions that we initiate now, but they finish later.
+
+For instance, one such function is the `setTimeout` function.
+
+There are other real-world examples of asynchronous actions, e.g. loading scripts and modules (we'll cover them in later chapters).
+
+Take a look at the function `loadScript(src)`, that loads a script with the given `src`:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js
function loadScript(src) {
+ // creates a
@@ -322,11 +402,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.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
### Совместимость, "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:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```html run
@@ -56,17 +91,26 @@ drawHtmlTree(node1, 'div.domtree', 690, 320);
Каждый узел этого дерева - это объект.
+<<<<<<< HEAD
Теги являются *узлами-элементами* (или просто элементами). Они образуют структуру дерева: `` -- это корневой узел, `` и `` его дочерние узлы и т.д.
+=======
+Tags are *element nodes* (or just elements) and form the tree structure: `` is at the root, then `` and `` are its children, etc.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Текст внутри элементов образует *текстовые узлы*, обозначенные как `#text`. Текстовый узел содержит в себе только строку текста. У него не может быть потомков, т.е. он находится всегда на самом нижнем уровне.
+<<<<<<< HEAD
Например, в теге `` есть текстовый узел `"О лосях"`.
+=======
+For instance, the `` tag has the text `"About elk"`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Обратите внимание на специальные символы в текстовых узлах:
- перевод строки: `↵` (в JavaScript он обозначается как `\n`)
- пробел: `␣`
+<<<<<<< HEAD
Пробелы и переводы строки -- это полноправные символы, как буквы и цифры. Они образуют текстовые узлы и становятся частью дерева DOM. Так, в примере выше в теге `` есть несколько пробелов перед ``, которые образуют текстовый узел `#text` (он содержит в себе только перенос строки и несколько пробелов).
Существует всего два исключения из этого правила:
@@ -74,18 +118,35 @@ drawHtmlTree(node1, 'div.domtree', 690, 320);
2. Если мы записываем что-либо после закрывающего тега ``, браузер автоматически перемещает эту запись в конец `body`, поскольку спецификация HTML требует, чтобы всё содержимое было внутри ``. Поэтому после закрывающего тега `` не может быть никаких пробелов.
В остальных случаях всё просто -- если в документе есть пробелы (или любые другие символы), они становятся текстовыми узлами дерева DOM, и если мы их удалим, то в DOM их тоже не будет.
+=======
+Spaces and newlines are totally valid characters, like letters and digits. They form text nodes and become a part of the DOM. So, for instance, in the example above the `` tag contains some spaces before ``, and that text becomes a `#text` node (it contains a newline and some spaces only).
+
+There are only two top-level exclusions:
+1. Spaces and newlines before `` are ignored for historical reasons.
+2. If we put something after ``, then that is automatically moved inside the `body`, at the end, as the HTML spec requires that all content must be inside ``. So there can't be any spaces after ``.
+
+In other cases everything's straightforward -- if there are spaces (just like any character) in the document, then they become text nodes in the DOM, and if we remove them, then there won't be any.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Здесь пробельных текстовых узлов нет:
```html no-beautify
+<<<<<<< HEAD
О лосяхПравда о лосях.
+=======
+About elkThe truth about elk.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```
@@ -100,11 +161,19 @@ drawHtmlTree(node2, 'div.domtree', 690, 210);
## Автоисправление
+<<<<<<< HEAD
Если браузер сталкивается с некорректно написанным HTML-кодом, он автоматически корректирует его при построении DOM.
Например, в начале документа всегда должен быть тег ``. Даже если его нет в документе -- он будет в дереве DOM, браузер его создаст. То же самое касается и тега ``.
Например, если HTML-файл состоит из единственного слова `"Привет"`, браузер обернёт его в теги `` и ``, добавит необходимый тег ``, и DOM будет выглядеть так:
+=======
+If the browser encounters malformed HTML, it automatically corrects it when making the DOM.
+
+For instance, the top tag is always ``. Even if it doesn't exist in the document, it will exist in the DOM, because the browser will create it. The same goes for ``.
+
+As an example, if the HTML file is the single word `"Hello"`, the browser will wrap it into `` and ``, and add the required ``, and the DOM will be:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
@@ -117,7 +186,11 @@ drawHtmlTree(node3, 'div.domtree', 690, 150);
При генерации DOM браузер самостоятельно обрабатывает ошибки в документе, закрывает теги и так далее.
+<<<<<<< HEAD
Есть такой документ с незакрытыми тегами:
+=======
+A document with unclosed tags:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```html no-beautify
Папа
```
+<<<<<<< HEAD
...Но DOM будет нормальным, потому что браузер сам закроет теги и восстановит отсутствующие детали:
+=======
+...will become a normal DOM as the browser reads tags and restores the missing parts:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
@@ -136,8 +213,13 @@ let node4 = {"name":"HTML","nodeType":1,"children":[{"name":"HEAD","nodeType":1,
drawHtmlTree(node4, 'div.domtree', 690, 360);
+<<<<<<< HEAD
````warn header="Таблицы всегда содержат ``"
Важный "особый случай" -- работа с таблицами. По стандарту DOM у них должен быть ``, но в HTML их можно написать (официально) без него. В этом случае браузер добавляет `` в DOM самостоятельно.
+=======
+````warn header="Tables always have ``"
+An interesting "special case" is tables. By the DOM specification they must have ``, but HTML text may (officially) omit it. Then the browser creates `` in the DOM automatically.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Для такого HTML:
@@ -167,7 +249,11 @@ drawHtmlTree(node5, 'div.domtree', 600, 200);
+<<<<<<< HEAD
Правда о лосях.
+=======
+ The truth about elk.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Лось -- животное хитрое
*!*
@@ -182,7 +268,11 @@ drawHtmlTree(node5, 'div.domtree', 600, 200);
@@ -199,32 +289,51 @@ drawHtmlTree(node6, 'div.domtree', 690, 500);
Существует [12 типов узлов](https://dom.spec.whatwg.org/#node). Но на практике мы в основном работаем с 4 из них:
+<<<<<<< HEAD
1. `document` -- "входная точка" в DOM.
2. узлы-элементы -- HTML-теги, основные строительные блоки.
3. текстовые узлы -- содержат текст.
4. комментарии -- иногда в них можно включить информацию, которая не будет показана, но доступна в DOM для чтения JS.
+=======
+1. `document` -- the "entry point" into DOM.
+2. element nodes -- HTML-tags, the tree building blocks.
+3. text nodes -- contain text.
+4. comments -- sometimes we can put information there, it won't be shown, but JS can read it from the DOM.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
## Поэкспериментируйте сами
+<<<<<<< HEAD
Чтобы посмотреть структуру DOM в реальном времени, попробуйте [Live DOM Viewer](http://software.hixie.ch/utilities/js/live-dom-viewer/). Просто введите что-нибудь в поле, и ниже вы увидите, как меняется DOM.
+=======
+To see the DOM structure in real-time, try [Live DOM Viewer](http://software.hixie.ch/utilities/js/live-dom-viewer/). Just type in the document, and it will show up as a DOM at an instant.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Другой способ исследовать DOM - это использовать инструменты разработчика браузера. Это то, что мы каждый день делаем при разработке.
+<<<<<<< HEAD
Для этого откройте страницу [elks.html](elks.html), включите инструменты разработчика и перейдите на вкладку Elements.
+=======
+To do so, open the web page [elk.html](elk.html), turn on the browser developer tools and switch to the Elements tab.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Выглядит примерно так:
-
+
Вы можете увидеть DOM, понажимать на элементы, детально рассмотреть их и так далее.
Обратите внимание, что структура DOM в инструментах разработчика отображается в упрощённом виде. Текстовые узлы показаны как простой текст. И кроме пробелов нет никаких "пустых" текстовых узлов. Ну и отлично, потому что большую часть времени нас будут интересовать узлы-элементы.
+<<<<<<< HEAD
Клик по этой кнопке в левом верхнем углу инспектора позволяет при помощи мыши (или другого устройства ввода) выбрать элемент на веб-странице и "проинспектировать" его (браузер сам найдёт и отметит его во вкладке Elements). Этот способ отлично подходит, когда у нас огромная HTML-страница (и соответствующий ей огромный DOM), и мы хотим увидеть, где находится интересующий нас элемент.
+=======
+Clicking the button in the left-upper corner allows us to choose a node from the webpage using a mouse (or other pointer devices) and "inspect" it (scroll to it in the Elements tab). This works great when we have a huge HTML page (and corresponding huge DOM) and would like to see the place of a particular element in it.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Есть и другой способ сделать это: можно кликнуть на странице по элементу правой кнопкой мыши и в контекстном меню выбрать "Inspect".
-
+
В правой части инструментов разработчика находятся следующие подразделы:
- **Styles** -- здесь мы видим CSS, применённый к текущему элементу: правило за правилом, включая встроенные стили (выделены серым). Почти всё можно отредактировать на месте, включая размеры, внешние и внутренние отступы.
@@ -247,15 +356,19 @@ drawHtmlTree(node6, 'div.domtree', 690, 500);
Теперь мы можем запускать на них команды. Например `$0.style.background = 'red'` сделает выбранный элемент красным, как здесь:
-
+
Это мы посмотрели как получить узел из Elements в Console.
Есть и обратный путь: если есть переменная `node`, ссылающаяся на DOM-узел, можно использовать в консоли команду `inspect(node)`, чтобы увидеть этот элемент во вкладке Elements.
+<<<<<<< HEAD
Или мы можем просто вывести DOM-узел в консоль и исследовать "на месте", как `document.body` ниже:
+=======
+Or we can just output the DOM node in the console and explore "in-place", like `document.body` below:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
-
+
Это может быть полезно для отладки. В следующей главе мы рассмотрим доступ и изменение DOM при помощи JavaScript.
@@ -273,4 +386,8 @@ HTML/XML документы представлены в браузере в ви
Здесь мы рассмотрели основы, наиболее часто используемые и важные действия для начала разработки. Подробную документацию по инструментам разработки Chrome Developer Tools можно найти на странице . Лучший способ изучить инструменты -- походить по разным вкладкам, почитать меню: большинство действий очевидны для пользователя. Позже, когда вы немного их изучите, прочитайте документацию и узнайте то, что осталось.
+<<<<<<< HEAD
У DOM-узлов есть свойства и методы, которые позволяют выбирать любой из элементов, изменять, перемещать их на странице и многое другое. Мы вернёмся к ним в последующих разделах.
+=======
+DOM nodes have properties and methods that allow us to travel between them, modify them, move around the page, and more. We'll get down to them in the next chapters.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
diff --git a/2-ui/1-document/02-dom-nodes/domconsole0.svg b/2-ui/1-document/02-dom-nodes/domconsole0.svg
new file mode 100644
index 0000000000..c0096060aa
--- /dev/null
+++ b/2-ui/1-document/02-dom-nodes/domconsole0.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/2-ui/1-document/02-dom-nodes/domconsole1.svg b/2-ui/1-document/02-dom-nodes/domconsole1.svg
new file mode 100644
index 0000000000..db92359d5d
--- /dev/null
+++ b/2-ui/1-document/02-dom-nodes/domconsole1.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/2-ui/1-document/02-dom-nodes/elks.html b/2-ui/1-document/02-dom-nodes/elk.html
similarity index 54%
rename from 2-ui/1-document/02-dom-nodes/elks.html
rename to 2-ui/1-document/02-dom-nodes/elk.html
index 07bb33f7a4..bc7d419a48 100644
--- a/2-ui/1-document/02-dom-nodes/elks.html
+++ b/2-ui/1-document/02-dom-nodes/elk.html
@@ -1,7 +1,11 @@
+<<<<<<< HEAD:2-ui/1-document/02-dom-nodes/elks.html
Правда о лосях.
+=======
+ The truth about elk.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a:2-ui/1-document/02-dom-nodes/elk.html
Лось -- животное хитрое
diff --git a/2-ui/1-document/02-dom-nodes/elk.svg b/2-ui/1-document/02-dom-nodes/elk.svg
new file mode 100644
index 0000000000..19ea221d29
--- /dev/null
+++ b/2-ui/1-document/02-dom-nodes/elk.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/2-ui/1-document/02-dom-nodes/inspect.svg b/2-ui/1-document/02-dom-nodes/inspect.svg
new file mode 100644
index 0000000000..658ee5ea26
--- /dev/null
+++ b/2-ui/1-document/02-dom-nodes/inspect.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/2-ui/1-document/03-dom-navigation/article.md b/2-ui/1-document/03-dom-navigation/article.md
index ae7e533532..101260a78e 100644
--- a/2-ui/1-document/03-dom-navigation/article.md
+++ b/2-ui/1-document/03-dom-navigation/article.md
@@ -149,7 +149,11 @@ elem.childNodes[elem.childNodes.length - 1] === elem.lastChild
Первый пункт - это хорошо для нас. Второй - бывает неудобен, но можно пережить. Если нам хочется использовать именно методы массива, то мы можем создать настоящий массив из коллекции, используя `Array.from`:
```js run
+<<<<<<< HEAD
alert( Array.from(document.body.childNodes).filter ); // сделали массив
+=======
+ alert( Array.from(document.body.childNodes).filter ); // function
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```
```warn header="DOM-коллекции -- только для чтения"
@@ -201,9 +205,15 @@ DOM-коллекции, и даже более -- *все* навигацион
Например:
+<<<<<<< HEAD
```js
// родителем является
alert( document.body.parentNode === document.documentElement ); // выведет true
+=======
+```js run
+// parent of is
+alert( document.body.parentNode === document.documentElement ); // true
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
// после идёт
alert( document.head.nextSibling ); // HTMLBodyElement
@@ -224,10 +234,17 @@ alert( document.body.previousSibling ); // HTMLHeadElement
Эти ссылки похожи на те, что раньше, только в ряде мест стоит слово `Element`:
+<<<<<<< HEAD
- `children` -- коллекция детей, которые являются элементами.
- `firstElementChild`, `lastElementChild` -- первый и последний дочерний элемент.
- `previousElementSibling`, `nextElementSibling` -- соседи-элементы.
- `parentElement` -- родитель-элемент.
+=======
+- `children` -- only those children that are element nodes.
+- `firstElementChild`, `lastElementChild` -- first and last element children.
+- `previousElementSibling`, `nextElementSibling` -- neighbor elements.
+- `parentElement` -- parent element.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
````smart header="Зачем нужен `parentElement`? Разве может родитель быть *не* элементом?"
Свойство `parentElement` возвращает родитель-элемент, а `parentNode` возвращает "любого родителя". Обычно эти свойства одинаковы: они оба получают родителя.
@@ -280,12 +297,21 @@ while(elem = elem.parentElement) { // идти наверх до
Некоторые типы DOM-элементов предоставляют для удобства дополнительные свойства, специфичные для их типа.
+<<<<<<< HEAD
Таблицы -- отличный пример таких элементов.
**Элемент `
`**, в дополнение к свойствам, о которых речь шла выше, поддерживает следующие:
- `table.rows` -- коллекция строк `
` таблицы.
- `table.caption/tHead/tFoot` -- ссылки на элементы таблицы `
`, `
`, `
`.
- `table.tBodies` -- коллекция элементов таблицы `` (по спецификации их может быть больше одного).
+=======
+Tables are a great example of that, and represent a particularly important case:
+
+**The `
`** element supports (in addition to the given above) these properties:
+- `table.rows` -- the collection of `
` elements of the table.
+- `table.caption/tHead/tFoot` -- references to elements `
`, `
`, `
`.
+- `table.tBodies` -- the collection of `` elements (can be many according to the standard, but there will always be at least one -- even if it is not in the source HTML, the browser will put it in the DOM).
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
**``, ``, ``** предоставляют свойство `rows`:
- `tbody.rows` -- коллекция строк `
` секции.
@@ -311,8 +337,14 @@ while(elem = elem.parentElement) { // идти наверх до
```
+<<<<<<< HEAD
Почему атрибут может быть предпочтительнее таких классов, как `.order-state-new`, `.order-state-pending`, `order-state-canceled`?
Это потому, что атрибутом удобнее управлять. Состояние может быть изменено достаточно просто:
+=======
+Why would using an attribute be preferable to having classes like `.order-state-new`, `.order-state-pending`, `order-state-canceled`?
+
+Because an attribute is more convenient to manage. The state can be changed as easy as:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js
// немного проще, чем удаление старого/добавление нового класса
div.setAttribute('order-state', 'canceled');
```
+<<<<<<< HEAD
Но с пользовательскими атрибутами могут возникнуть проблемы. Что если мы используем нестандартный атрибут для наших целей, а позже он появится в стандарте и будет выполнять какую-то функцию? Язык HTML живой, он растёт, появляется больше атрибутов, чтобы удовлетворить потребности разработчиков. В этом случае могут возникнуть неожиданные эффекты.
+=======
+But there may be a possible problem with custom attributes. What if we use a non-standard attribute for our purposes and later the standard introduces it and makes it do something? The HTML language is alive, it grows, and more attributes appear to suit the needs of developers. There may be unexpected effects in such case.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Чтобы избежать конфликтов, существуют атрибуты вида [data-*](https://html.spec.whatwg.org/#embedding-custom-non-visible-data-with-the-data-*-attributes).
diff --git a/2-ui/1-document/07-modifying-document/12-sort-table/solution.md b/2-ui/1-document/07-modifying-document/12-sort-table/solution.md
index 436efc10af..b2c67afd3e 100644
--- a/2-ui/1-document/07-modifying-document/12-sort-table/solution.md
+++ b/2-ui/1-document/07-modifying-document/12-sort-table/solution.md
@@ -1,14 +1,13 @@
Решение короткое, но может показаться немного сложным, поэтому здесь я предоставлю подробные комментарии:
-
```js
-let sortedRows = Array.from(table.rows)
- .slice(1)
- .sort((rowA, rowB) => rowA.cells[0].innerHTML > rowB.cells[0].innerHTML ? 1 : -1);
+let sortedRows = Array.from(table.tBodies[0].rows) // 1
+ .sort((rowA, rowB) => rowA.cells[0].innerHTML.localeCompare(rowB.cells[0].innerHTML));
-table.tBodies[0].append(...sortedRows);
+table.tBodies[0].append(...sortedRows); // (3)
```
+<<<<<<< HEAD
1. Получим все `
`, как `table.querySelectorAll('tr')`, затем сделаем массив из них, потому что нам понадобятся методы массива.
2. Первый TR (`table.rows[0]`) -- это заголовок таблицы, поэтому мы берём `.slice(1)`.
3. Затем отсортируем их по содержимому в первом `
` (по имени).
@@ -17,3 +16,14 @@ table.tBodies[0].append(...sortedRows);
Таблицы всегда имеют неявный элемент
, поэтому нам нужно получить его и вставить в него: простой `table.append(...)` потерпит неудачу.
Обратите внимание: нам не нужно их удалять, просто "вставляем их заново", они автоматически покинут старое место.
+=======
+The step-by-step algorthm:
+
+1. Get all `
`, from `
`.
+2. Then sort them comparing by the content of the first `
` (the name field).
+3. Now insert nodes in the right order by `.append(...sortedRows)`.
+
+We don't have to remove row elements, just "re-insert", they leave the old place automatically.
+
+P.S. In our case, there's an explicit `
` in the table, but even if HTML table doesn't have ``, the DOM structure always has it.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
diff --git a/2-ui/1-document/07-modifying-document/12-sort-table/solution.view/index.html b/2-ui/1-document/07-modifying-document/12-sort-table/solution.view/index.html
index b47cf85582..70c1016f26 100644
--- a/2-ui/1-document/07-modifying-document/12-sort-table/solution.view/index.html
+++ b/2-ui/1-document/07-modifying-document/12-sort-table/solution.view/index.html
@@ -1,7 +1,6 @@
-
-
+<<<<<<< HEAD
+```
Может быть больше строк.
diff --git a/2-ui/1-document/07-modifying-document/5-why-aaa/task.md b/2-ui/1-document/07-modifying-document/5-why-aaa/task.md
index b92c81e133..944053d5fa 100644
--- a/2-ui/1-document/07-modifying-document/5-why-aaa/task.md
+++ b/2-ui/1-document/07-modifying-document/5-why-aaa/task.md
@@ -4,7 +4,15 @@ importance: 1
# Почему остаётся "aaa"?
+<<<<<<< HEAD
Запустите этот пример. Почему вызов `remove` не удалил текст `"aaa"`?
+=======
+In the example below, the call `table.remove()` removes the table from the document.
+
+But if you run it, you can see that the text `"aaa"` is still visible.
+
+Why does that happen?
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```html height=100 run
diff --git a/2-ui/1-document/07-modifying-document/9-calendar-table/solution.md b/2-ui/1-document/07-modifying-document/9-calendar-table/solution.md
index c0e15c7b2a..9bbd6dee05 100644
--- a/2-ui/1-document/07-modifying-document/9-calendar-table/solution.md
+++ b/2-ui/1-document/07-modifying-document/9-calendar-table/solution.md
@@ -2,8 +2,16 @@
Алгоритм:
+<<<<<<< HEAD
1. Создать заголовок таблицы с `
` и именами дней недели.
2. Создать объект даты `d = new Date(year, month-1)`. Это первый день месяца `month` (с учётом того, что месяцы в JS начинаются от 0, а не от 1).
3. Ячейки первого ряда пустые от начала и до дня недели `d.getDay()`, с которого начинается месяц. Заполним `
`.
4. Увеличить день в `d`: `d.setDate(d.getDate()+1)`. Если `d.getMonth()` ещё не в следующем месяце, то добавим новую ячейку `
` в календарь. Если это воскресенье, то добавим новую строку "</tr><tr>".
5. Если месяц закончился, но строка таблицы ещё не заполнена, добавим в неё пустые `
`, чтобы сделать в календаре красивые пустые квадратики.
+=======
+1. Create the table header with `
` and weekday names.
+2. Create the date object `d = new Date(year, month-1)`. That's the first day of `month` (taking into account that months in JavaScript start from `0`, not `1`).
+3. First few cells till the first day of the month `d.getDay()` may be empty. Let's fill them in with `
`.
+4. Increase the day in `d`: `d.setDate(d.getDate()+1)`. If `d.getMonth()` is not yet the next month, then add the new cell `
` to the calendar. If that's a Sunday, then add a newline "</tr><tr>".
+5. If the month has finished, but the table row is not yet full, add empty `
` into it, to make it square.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
diff --git a/2-ui/1-document/07-modifying-document/article.md b/2-ui/1-document/07-modifying-document/article.md
index 09c71f59d5..88314bfa56 100644
--- a/2-ui/1-document/07-modifying-document/article.md
+++ b/2-ui/1-document/07-modifying-document/article.md
@@ -1,12 +1,20 @@
# Изменение документа
+<<<<<<< HEAD
Модификации DOM - это ключ к созданию "живых" страниц.
+=======
+DOM modification is the key to creating "live" pages.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Здесь мы увидим, как создавать новые элементы "на лету" и изменять уже существующие.
## Пример: показать сообщение
+<<<<<<< HEAD
Рассмотрим методы на примере - а именно, добавим на страницу сообщение, которое будет выглядеть получше, чем `alert`.
+=======
+Let's demonstrate using an example. We'll add a message on the page that looks nicer than `alert`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Вот такое:
@@ -28,7 +36,11 @@
*/!*
```
+<<<<<<< HEAD
Это был пример HTML. Теперь давайте создадим такой же `div`, используя JavaScript (предполагаем, что стили в HTML или во внешнем CSS-файле).
+=======
+That was the HTML example. Now let's create the same `div` with JavaScript (assuming that the styles are in the HTML/CSS already).
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
## Создание элемента
@@ -48,21 +60,45 @@ DOM-узел можно создать двумя методами:
let textNode = document.createTextNode('А вот и я');
```
+<<<<<<< HEAD
### Создание сообщения
В нашем случае сообщение - это `div` с классом `alert` и HTML в нём:
+=======
+Most of the time we need to create element nodes, such as the `div` for the message.
+
+### Creating the message
+
+Creating the message div takes 3 steps:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```js
+// 1. Create
element
let div = document.createElement('div');
+
+// 2. Set its class to "alert"
div.className = "alert";
+<<<<<<< HEAD
div.innerHTML = "Всем привет! Вы прочитали важное сообщение.";
```
Мы создали элемент, но пока он только в переменной. Мы не можем видеть его на странице, поскольку он не является частью документа.
+=======
+
+// 3. Fill it with the content
+div.innerHTML = "Hi there! You've read an important message.";
+```
+
+We've created the element. But as of now it's only in a variable named `div`, not in the page yet. So we can't see it.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
## Методы вставки
+<<<<<<< HEAD
Чтобы наш `div` появился, нам нужно вставить его где-нибудь в `document`. Например, в `document.body`.
+=======
+To make the `div` show up, we need to insert it somewhere into `document`. For instance, into `` element, referenced by `document.body`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Для этого есть метод `append`, в нашем случае: `document.body.append(div)`.
@@ -90,6 +126,7 @@ div.innerHTML = "Всем привет! Вы прочитали
```
+<<<<<<< HEAD
Вот методы для различных вариантов вставки:
- `node.append(...nodes or strings)` -- добавляет узлы или строки в конец `node`,
@@ -99,6 +136,23 @@ div.innerHTML = "Всем привет! Вы прочитали
- `node.replaceWith(...nodes or strings)` –- заменяет `node` заданными узлами или строками.
Вот пример использования этих методов, чтобы добавить новые элементы в список и текст до/после него:
+=======
+Here we called `append` on `document.body`, but we can call `append` method on any other element, to put another element into it. For instance, we can append something to `
` by calling `div.append(anotherElement)`.
+
+Here are more insertion methods, they specify different places where to insert:
+
+- `node.append(...nodes or strings)` -- append nodes or strings *at the end* of `node`,
+- `node.prepend(...nodes or strings)` -- insert nodes or strings *at the beginning* of `node`,
+- `node.before(...nodes or strings)` –- insert nodes or strings *before* `node`,
+- `node.after(...nodes or strings)` –- insert nodes or strings *after* `node`,
+- `node.replaceWith(...nodes or strings)` –- replaces `node` with the given nodes or strings.
+
+Arguments of these methods are an arbitrary list of DOM nodes to insert, or text strings (that become text nodes automatically).
+
+Let's see them in action.
+
+Here's an example of using these methods to add items to a list and the text before/after it:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```html autorun
@@ -121,7 +175,11 @@ div.innerHTML = "Всем привет! Вы прочитали
```
+<<<<<<< HEAD
Наглядная иллюстрация того, куда эти методы вставляют:
+=======
+Here's a visual picture of what the methods do:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a

@@ -139,7 +197,11 @@ before
after
```
+<<<<<<< HEAD
Эти методы могут вставлять несколько узлов и текстовых фрагментов за один вызов.
+=======
+As said, these methods can insert multiple nodes and text pieces in a single call.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Например, здесь вставляется строка и элемент:
@@ -150,7 +212,11 @@ after
```
+<<<<<<< HEAD
Весь текст вставляется *как текст*.
+=======
+Please note: the text is inserted "as text", not "as HTML", with proper escaping of characters such as `<`, `>`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Поэтому финальный HTML будет:
@@ -166,7 +232,11 @@ after
Поэтому эти методы могут использоваться только для вставки DOM-узлов или текстовых фрагментов.
+<<<<<<< HEAD
А что, если мы хотим вставить HTML именно "как html", со всеми тегами и прочим, как делает это `elem.innerHTML`?
+=======
+But what if we'd like to insert an HTML string "as html", with all tags and stuff working, in the same manner as `elem.innerHTML` does it?
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
## insertAdjacentHTML/Text/Element
@@ -199,7 +269,11 @@ after
Пока
```
+<<<<<<< HEAD
Так мы можем добавлять произвольный HTML на страницу.
+=======
+That's how we can append arbitrary HTML to the page.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Варианты вставки:
@@ -532,6 +606,7 @@ ul.append(...getListContent()); // append + оператор "..." = друзь
Все эти методы возвращают `node`.
+<<<<<<< HEAD
- Если нужно вставить фрагмент HTML, то `elem.insertAdjacentHTML(where, html)` вставляет в зависимости от `where`:
- `"beforebegin"` -- вставляет `html` прямо перед `elem`,
- `"afterbegin"` -- вставляет `html` в `elem` в начало,
@@ -539,6 +614,15 @@ ul.append(...getListContent()); // append + оператор "..." = друзь
- `"afterend"` -- вставляет `html` сразу после `elem`.
Также существуют похожие методы `elem.insertAdjacentText` и `elem.insertAdjacentElement`, они вставляют текстовые строки и элементы, но они редко используются.
+=======
+- Given some HTML in `html`, `elem.insertAdjacentHTML(where, html)` inserts it depending on the value of `where`:
+ - `"beforebegin"` -- insert `html` right before `elem`,
+ - `"afterbegin"` -- insert `html` into `elem`, at the beginning,
+ - `"beforeend"` -- insert `html` into `elem`, at the end,
+ - `"afterend"` -- insert `html` right after `elem`.
+
+ Also there are similar methods, `elem.insertAdjacentText` and `elem.insertAdjacentElement`, that insert text strings and elements, but they are rarely used.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
- Чтобы добавить HTML на страницу до завершения её загрузки:
- `document.write(html)`
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 1701d5832a..bd589dcf8d 100644
--- a/2-ui/1-document/08-styles-and-classes/article.md
+++ b/2-ui/1-document/08-styles-and-classes/article.md
@@ -249,8 +249,13 @@ pseudo
```smart header="Вычисленное (computed) и окончательное (resolved) значения"
Есть две концепции в [CSS](https://drafts.csswg.org/cssom/#resolved-values):
+<<<<<<< HEAD
1. *Вычисленное* (computed) значение – это то, которое получено после применения всех CSS-правил и CSS-наследования. Например, `height:1em` или `font-size:125%`.
2. *Окончательное* ([resolved](https://drafts.csswg.org/cssom/#resolved-values)) значение – непосредственно применяемое к элементу. Значения `1em` или `125%` являются относительными. Браузер берёт вычисленное значение и делает все единицы измерения фиксированными и абсолютными, например, `height:20px` или `font-size:16px`. Для геометрических свойств разрешённые значения могут иметь плавающую точку, например, `width:50.5px`.
+=======
+1. A *computed* style value is the value after all CSS rules and CSS inheritance is applied, as the result of the CSS cascade. It can look like `height:1em` or `font-size:125%`.
+2. A *resolved* style value is the one finally applied to the element. Values like `1em` or `125%` are relative. The browser takes the computed value and makes all units fixed and absolute, for instance: `height:20px` or `font-size:16px`. For geometry properties resolved values may have a floating point, like `width:50.5px`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Давным-давно `getComputedStyle` был создан для получения вычисленных значений, но оказалось, что окончательные значения гораздо удобнее, и стандарт изменился.
@@ -282,7 +287,11 @@ pseudo
Но `getComputedStyle` не даёт доступ к этой информации, чтобы произвольная страница не могла определить, посещал ли пользователь ту или иную ссылку, проверив стили.
+<<<<<<< HEAD
JavaScript не видит стили, применяемые с помощью `:visited`. Кроме того, в CSS есть ограничение, которое запрещает в целях безопасности применять к `:visited` CSS-стили, изменяющие геометрию элемента. Это гарантирует, что нет обходного пути для "злой" страницы проверить, была ли ссылка посещена и, следовательно, нарушить конфиденциальность.
+=======
+JavaScript may not see the styles applied by `:visited`. And also, there's a limitation in CSS that forbids applying geometry-changing styles in `:visited`. That's to guarantee that there's no side way for an evil page to test if a link was visited and hence to break the privacy.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```
## Итого
diff --git a/2-ui/1-document/09-size-and-scroll/1-get-scroll-height-bottom/task.md b/2-ui/1-document/09-size-and-scroll/1-get-scroll-height-bottom/task.md
index 9f806ecf6d..3255c3e91e 100644
--- a/2-ui/1-document/09-size-and-scroll/1-get-scroll-height-bottom/task.md
+++ b/2-ui/1-document/09-size-and-scroll/1-get-scroll-height-bottom/task.md
@@ -4,7 +4,11 @@ importance: 5
# Найти размер прокрутки снизу
+<<<<<<< HEAD
Свойство `elem.scrollTop` содержит размер прокрученной области при отсчёте сверху. А как подсчитать размер прокрутки снизу (назовём его `scrollBottom`)?
+=======
+The `elem.scrollTop` property is the size of the scrolled out part from the top. How to get the size of the bottom scroll (let's call it `scrollBottom`)?
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Напишите соответствующее выражение для произвольного элемента `elem`.
diff --git a/2-ui/1-document/09-size-and-scroll/4-put-ball-in-center/ball-half/index.html b/2-ui/1-document/09-size-and-scroll/4-put-ball-in-center/ball-half/index.html
index 79d0b1f845..61a4e9e290 100755
--- a/2-ui/1-document/09-size-and-scroll/4-put-ball-in-center/ball-half/index.html
+++ b/2-ui/1-document/09-size-and-scroll/4-put-ball-in-center/ball-half/index.html
@@ -20,7 +20,7 @@
diff --git a/2-ui/1-document/09-size-and-scroll/4-put-ball-in-center/solution.md b/2-ui/1-document/09-size-and-scroll/4-put-ball-in-center/solution.md
index 12cf07d69e..c57bce9e5a 100644
--- a/2-ui/1-document/09-size-and-scroll/4-put-ball-in-center/solution.md
+++ b/2-ui/1-document/09-size-and-scroll/4-put-ball-in-center/solution.md
@@ -24,17 +24,30 @@ ball.style.left = Math.round(field.clientWidth / 2 - ball.offsetWidth / 2) + 'px
ball.style.top = Math.round(field.clientHeight / 2 - ball.offsetHeight / 2) + 'px';
```
+<<<<<<< HEAD
**Внимание, подводный камень!**
+=======
+Now the ball is finally centered.
+
+````warn header="Attention: the pitfall!"
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Код выше стабильно работать не будет, потому что `` идёт без ширины/высоты:
```html
```
+````
Если браузеру неизвестны ширина и высота изображения (из атрибута HTML-тега или CSS-свойств), он считает их равными `0` до тех пор, пока изображение не загрузится.
+<<<<<<< HEAD
При первой загрузке браузер обычно кеширует изображения, так что при последующей загрузке оно будет доступно тут же, вместе с размерами. Но при первой загрузке значение ширины мяча `ball.offsetWidth` равно `0`. Это приводит к вычислению неверных координат.
+=======
+So the value of `ball.offsetWidth` will be `0` until the image loads. That leads to wrong coordinates in the code above.
+
+After the first load, the browser usually caches the image, and on reloads it will have the size immediately. But on the first load the value of `ball.offsetWidth` is `0`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Мы можем исправить это, добавив атрибуты `width/height` тегу ``:
diff --git a/2-ui/1-document/09-size-and-scroll/4-put-ball-in-center/solution.view/index.html b/2-ui/1-document/09-size-and-scroll/4-put-ball-in-center/solution.view/index.html
index c7712b25f8..78a68ffae8 100755
--- a/2-ui/1-document/09-size-and-scroll/4-put-ball-in-center/solution.view/index.html
+++ b/2-ui/1-document/09-size-and-scroll/4-put-ball-in-center/solution.view/index.html
@@ -26,8 +26,13 @@
diff --git a/2-ui/1-document/09-size-and-scroll/4-put-ball-in-center/task.md b/2-ui/1-document/09-size-and-scroll/4-put-ball-in-center/task.md
index 685edda8a3..b9960bec57 100644
--- a/2-ui/1-document/09-size-and-scroll/4-put-ball-in-center/task.md
+++ b/2-ui/1-document/09-size-and-scroll/4-put-ball-in-center/task.md
@@ -10,7 +10,11 @@ importance: 5
Каковы координаты центра поля?
+<<<<<<< HEAD
Вычислите их и используйте, чтобы поместить мяч в центр поля:
+=======
+Calculate them and use to place the ball into the center of the green field:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
[iframe src="solution" height=180]
diff --git a/2-ui/1-document/09-size-and-scroll/article.md b/2-ui/1-document/09-size-and-scroll/article.md
index 34ef7144c5..388b64e1aa 100644
--- a/2-ui/1-document/09-size-and-scroll/article.md
+++ b/2-ui/1-document/09-size-and-scroll/article.md
@@ -55,6 +55,7 @@
Эти свойства редко используются, но так как они являются "самыми внешними" метриками, мы начнём с них.
+<<<<<<< HEAD
В свойстве `offsetParent` находится предок элемента, который используется внутри браузера для вычисления координат при рендеринге.
То есть, ближайший предок, который удовлетворяет следующим условиям:
@@ -62,6 +63,15 @@
1. Является CSS-позиционированным (CSS-свойство `position` равно `absolute`, `relative`, `fixed` или `sticky`),
2. или `
`, `
`, `
`,
3. или ``.
+=======
+The `offsetParent` is the nearest ancestor that the browser uses for calculating coordinates during rendering.
+
+That's the nearest ancestor that is one of the following:
+
+1. CSS-positioned (`position` is `absolute`, `relative`, `fixed` or `sticky`), or
+2. `
`, `
`, or `
`, or
+3. ``.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Свойства `offsetLeft/offsetTop` содержат координаты x/y относительно верхнего левого угла `offsetParent`.
@@ -104,7 +114,11 @@
````smart header="Метрики для не показываемых элементов равны нулю."
Координаты и размеры в JavaScript устанавливаются только для видимых элементов.
+<<<<<<< HEAD
Если элемент (или любой его родитель) имеет `display:none` или отсутствует в документе, то все его метрики равны нулю (или `null`, если это `offsetParent`).
+=======
+If an element (or any of its ancestors) has `display:none` or is not in the document, then all geometry properties are zero (or `null` for `offsetParent`).
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Например, свойство `offsetParent` равно `null`, а `offsetWidth` и `offsetHeight` равны `0`, когда мы создали элемент, но ещё не вставили его в документ, или если у элемента (или у его родителя) `display:none`.
@@ -211,7 +225,11 @@ element.style.height = `${element.scrollHeight}px`;
Кликни Меня 1 2 3 4 5 6 7 8 9
```
+<<<<<<< HEAD
Установка значения `scrollTop` на `0` или `Infinity` прокрутит элемент в самый верх/низ соответственно.
+=======
+Setting `scrollTop` to `0` or a big value, such as `1e9` will make the element scroll to the very top/bottom respectively.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
````
## Не стоит брать width/height из CSS
@@ -243,9 +261,15 @@ alert( getComputedStyle(elem).width ); // показывает CSS-ширину
```
+<<<<<<< HEAD
Конечно, с точки зрения CSS `width:auto` – совершенно нормально, но нам-то в JavaScript нужен конкретный размер в `px`, который мы могли бы использовать для вычислений. Получается, что в данном случае ширина из CSS вообще бесполезна.
Есть и ещё одна причина: полоса прокрутки. Бывает, без полосы прокрутки код работает прекрасно, но стоит ей появиться, как начинают проявляться баги. Так происходит потому, что полоса прокрутки "отъедает" место от области внутреннего содержимого в некоторых браузерах. Таким образом, реальная ширина содержимого *меньше* CSS-ширины. Как раз это и учитывают свойства `clientWidth/clientHeight`.
+=======
+ From the CSS standpoint, `width:auto` is perfectly normal, but in JavaScript we need an exact size in `px` that we can use in calculations. So here CSS width is useless.
+
+And there's one more reason: a scrollbar. Sometimes the code that works fine without a scrollbar becomes buggy with it, because a scrollbar takes the space from the content in some browsers. So the real width available for the content is *less* than CSS width. And `clientWidth/clientHeight` take that into account.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
...Но с `getComputedStyle(elem).width` ситуация иная. Некоторые браузеры (например, Chrome) возвращают реальную внутреннюю ширину с вычетом ширины полосы прокрутки, а некоторые (например, Firefox) -- именно CSS-свойство (игнорируя полосу прокрутки). Эти кроссбраузерные отличия – ещё один повод не использовать `getComputedStyle`, а использовать свойства-метрики.
@@ -265,6 +289,7 @@ alert( getComputedStyle(elem).width ); // показывает CSS-ширину
У элементов есть следующие геометрические свойства (метрики):
+<<<<<<< HEAD
- `offsetParent` -- ближайший CSS-позиционированный родитель или ближайший `td`, `th`, `table`, `body`.
- `offsetLeft/offsetTop` -- позиция в пикселях верхнего левого угла относительно `offsetParent`.
- `offsetWidth/offsetHeight` -- "внешняя" ширина/высота элемента, включая рамки.
@@ -272,5 +297,14 @@ alert( getComputedStyle(elem).width ); // показывает CSS-ширину
- `clientWidth/clientHeight` -- ширина/высота содержимого вместе с внутренними отступами `padding`, но без полосы прокрутки.
- `scrollWidth/scrollHeight` -- ширины/высота содержимого, аналогично `clientWidth/Height`, но учитывают прокрученную, невидимую область элемента.
- `scrollLeft/scrollTop` -- ширина/высота прокрученной сверху части элемента, считается от верхнего левого угла.
+=======
+- `offsetParent` -- is the nearest positioned ancestor or `td`, `th`, `table`, `body`.
+- `offsetLeft/offsetTop` -- coordinates relative to the upper-left edge of `offsetParent`.
+- `offsetWidth/offsetHeight` -- "outer" width/height of an element including borders.
+- `clientLeft/clientTop` -- the distances from the upper-left outer corner to the upper-left inner (content + padding) corner. For left-to-right OS they are always the widths of left/top borders. For right-to-left OS the vertical scrollbar is on the left so `clientLeft` includes its width too.
+- `clientWidth/clientHeight` -- the width/height of the content including paddings, but without the scrollbar.
+- `scrollWidth/scrollHeight` -- the width/height of the content, just like `clientWidth/clientHeight`, but also include scrolled-out, invisible part of the element.
+- `scrollLeft/scrollTop` -- width/height of the scrolled out upper part of the element, starting from its upper-left corner.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Все свойства доступны только для чтения, кроме `scrollLeft/scrollTop`, изменение которых заставляет браузер прокручивать элемент.
diff --git a/2-ui/1-document/10-size-and-scroll-window/article.md b/2-ui/1-document/10-size-and-scroll-window/article.md
index 584af7223d..d099c321c0 100644
--- a/2-ui/1-document/10-size-and-scroll-window/article.md
+++ b/2-ui/1-document/10-size-and-scroll-window/article.md
@@ -1,8 +1,14 @@
# Размеры и прокрутка окна
+<<<<<<< HEAD
Как узнать ширину и высоту окна браузера? Как получить полную ширину и высоту документа, включая прокрученную часть? Как прокрутить страницу с помощью JavaScript?
Для большинства таких запросов мы можем использовать корневой элемент документа `document.documentElement`, который соответствует тегу ``. Однако есть дополнительные методы и особенности, которые необходимо учитывать.
+=======
+How do we find the width and height of the browser window? How do we get the full width and height of the document, including the scrolled out part? How do we scroll the page using JavaScript?
+
+For most such requests, we can use the root document element `document.documentElement`, that corresponds to the `` tag. But there are additional methods and peculiarities important enough to consider.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
## Ширина/высота окна
@@ -40,7 +46,11 @@ alert( document.documentElement.clientWidth ); // ширина окна за в
## Ширина/высота документа
+<<<<<<< HEAD
Теоретически, т.к. корневым элементом документа является `documentElement`, и он включает в себя всё содержимое, мы можем получить полный размер документа как `documentElement.scrollWidth/scrollHeight`.
+=======
+Theoretically, as the root document element is `document.documentElement`, and it encloses all the content, we could measure document full size as `document.documentElement.scrollWidth/scrollHeight`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Но именно на этом элементе, для страницы в целом, эти свойства работают не так, как предполагается. В Chrome/Safari/Opera, если нет прокрутки, то `documentElement.scrollHeight` может быть даже меньше, чем `documentElement.clientHeight`! С точки зрения элемента это невозможная ситуация.
@@ -63,8 +73,12 @@ alert('Полная высота документа с прокручиваем
Обычные элементы хранят текущее состояние прокрутки в `elem.scrollLeft/scrollTop`.
+<<<<<<< HEAD
Что же со страницей?
В большинстве браузеров мы можем обратиться к `documentElement.scrollLeft/Top`, за исключением основанных на старом WebKit (Safari), где есть ошибка ([5991](https://bugs.webkit.org/show_bug.cgi?id=5991)), и там нужно использовать `document.body` вместо `document.documentElement`.
+=======
+For document scroll `document.documentElement.scrollLeft/Top` works in most browsers, except older WebKit-based ones, like Safari (bug [5991](https://bugs.webkit.org/show_bug.cgi?id=5991)), where we should use `document.body` instead of `document.documentElement`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
К счастью, нам совсем не обязательно запоминать эти особенности, потому что текущую прокрутку можно прочитать из свойств `window.pageXOffset/pageYOffset`:
@@ -134,9 +148,9 @@ alert('Текущая прокрутка слева: ' + window.pageXOffset);
```online
Попробуйте сами:
-
+
-
+
Первая кнопка останавливает прокрутку, вторая возобновляет её.
```
diff --git a/2-ui/1-document/11-coordinates/1-find-point-coordinates/solution.md b/2-ui/1-document/11-coordinates/1-find-point-coordinates/solution.md
index ac013283ce..52917e8965 100644
--- a/2-ui/1-document/11-coordinates/1-find-point-coordinates/solution.md
+++ b/2-ui/1-document/11-coordinates/1-find-point-coordinates/solution.md
@@ -1,6 +1,10 @@
# Внешние углы
+<<<<<<< HEAD
Координаты внешних углов -- это как раз то, что возвращает функция [elem.getBoundingClientRect()](https://developer.mozilla.org/ru/docs/DOM/element.getBoundingClientRect).
+=======
+Outer corners are basically what we get from [elem.getBoundingClientRect()](https://developer.mozilla.org/en-US/docs/DOM/element.getBoundingClientRect).
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Координаты верхнего левого внешнего угла будут в переменной `answer1` и нижнего правого -- в `answer2`:
diff --git a/2-ui/1-document/11-coordinates/3-position-at-absolute/solution.view/index.html b/2-ui/1-document/11-coordinates/3-position-at-absolute/solution.view/index.html
index abb2f0b884..8ca186e110 100644
--- a/2-ui/1-document/11-coordinates/3-position-at-absolute/solution.view/index.html
+++ b/2-ui/1-document/11-coordinates/3-position-at-absolute/solution.view/index.html
@@ -28,8 +28,8 @@
let box = elem.getBoundingClientRect();
return {
- top: box.top + pageYOffset,
- left: box.left + pageXOffset
+ top: box.top + window.pageYOffset,
+ left: box.left + window.pageXOffset
};
}
diff --git a/2-ui/1-document/11-coordinates/4-position-inside-absolute/solution.view/index.html b/2-ui/1-document/11-coordinates/4-position-inside-absolute/solution.view/index.html
index 7e841397ba..b89db37900 100644
--- a/2-ui/1-document/11-coordinates/4-position-inside-absolute/solution.view/index.html
+++ b/2-ui/1-document/11-coordinates/4-position-inside-absolute/solution.view/index.html
@@ -26,8 +26,8 @@
let box = elem.getBoundingClientRect();
return {
- top: box.top + pageYOffset,
- left: box.left + pageXOffset
+ top: box.top + window.pageYOffset,
+ left: box.left + window.pageXOffset
};
}
diff --git a/2-ui/1-document/11-coordinates/article.md b/2-ui/1-document/11-coordinates/article.md
index dc5793e053..2a24d81cca 100644
--- a/2-ui/1-document/11-coordinates/article.md
+++ b/2-ui/1-document/11-coordinates/article.md
@@ -68,18 +68,30 @@ right:${r.right}
Заметим:
+<<<<<<< HEAD
- Координаты могут считаться с десятичной частью, например `10.5`. Это нормально, ведь браузер использует дроби в своих внутренних вычислениях. Мы не обязаны округлять значения при установке `style.left/top`.
- Координаты могут быть отрицательными. Например, если страница прокручена так, что элемент `elem` ушёл вверх за пределы окна, то вызов `elem.getBoundingClientRect().top` вернёт отрицательное значение.
+=======
+- Coordinates may be decimal fractions, such as `10.5`. That's normal, internally browser uses fractions in calculations. We don't have to round them when setting to `style.left/top`.
+- Coordinates may be negative. For instance, if the page is scrolled so that `elem` is now above the window, then `elem.getBoundingClientRect().top` is negative.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```smart header="Зачем вообще нужны зависимые свойства? Для чего существуют `top/left`, если есть `x/y`?"
С математической точки зрения, прямоугольник однозначно задаётся начальной точкой `(x,y)` и вектором направления `(width,height)`.
+<<<<<<< HEAD
Так что дополнительные зависимые свойства существуют лишь для удобства.
+=======
+Technically it's possible for `width/height` to be negative, that allows for "directed" rectangle, e.g. to represent mouse selection with properly marked start and end.
+
+Negative `width/height` values mean that the rectangle starts at its bottom-right corner and then "grows" left-upwards.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Что же касается `top/left`, то они на самом деле не всегда равны `x/y`. Технически, значения `width/height` могут быть отрицательными. Это позволяет задать "направленный" прямоугольник, например, для выделения мышью с отмеченным началом и концом.
То есть, отрицательные значения `width/height` означают, что прямоугольник "растет" влево-вверх из правого угла.
+<<<<<<< HEAD
Вот прямоугольник с отрицательными `width` и `height` (например, `width=-200`, `height=-100`):

@@ -93,6 +105,17 @@ right:${r.right}
Internet Explorer и Edge не поддерживают свойства `x/y` по историческим причинам.
Таким образом, мы можем либо сделать полифил (добавив соответствующие геттеры в `DomRect.prototype`), либо использовать `top/left`, так как это всегда одно и то же при положительных `width/height`, в частности - в результате вызова `elem.getBoundingClientRect()`.
+=======
+As you can see, `left/top` do not equal `x/y` in such case.
+
+In practice though, `elem.getBoundingClientRect()` always returns positive width/height, here we mention negative `width/height` only for you to understand why these seemingly duplicate properties are not actually duplicates.
+```
+
+```warn header="Internet Explorer: no support for `x/y`"
+Internet Explorer doesn't support `x/y` properties for historical reasons.
+
+So we can either make a polyfill (add getters in `DomRect.prototype`) or just use `top/left`, as they are always the same as `x/y` for positive `width/height`, in particular in the result of `elem.getBoundingClientRect()`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```
```warn header="Координаты right/bottom отличаются от одноимённых CSS-свойств"
@@ -216,8 +239,10 @@ function getCoords(elem) {
let box = elem.getBoundingClientRect();
return {
- top: box.top + pageYOffset,
- left: box.left + pageXOffset
+ top: box.top + window.pageYOffset,
+ right: box.right + window.pageXOffset,
+ bottom: box.bottom + window.pageYOffset,
+ left: box.left + window.pageXOffset
};
}
```
@@ -251,4 +276,8 @@ function createMessageUnder(elem, html) {
Координаты в контексте окна подходят для использования с `position:fixed`, а координаты относительно документа -- для использования с `position:absolute`.
+<<<<<<< HEAD
Каждая из систем координат имеет свои преимущества и недостатки. Иногда будет лучше применить одну, а иногда -- другую, как это и происходит с позиционированием в CSS, где мы выбираем между `absolute` и `fixed`.
+=======
+Both coordinate systems have their pros and cons; there are times we need one or the other one, just like CSS `position` `absolute` and `fixed`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
diff --git a/2-ui/2-events/01-introduction-browser-events/04-move-ball-field/solution.md b/2-ui/2-events/01-introduction-browser-events/04-move-ball-field/solution.md
index 04d9878ca3..f998a4c361 100644
--- a/2-ui/2-events/01-introduction-browser-events/04-move-ball-field/solution.md
+++ b/2-ui/2-events/01-introduction-browser-events/04-move-ball-field/solution.md
@@ -22,7 +22,11 @@
}
```
+<<<<<<< HEAD
Далее мы должны назначить корректные значения `ball.style.left/top`. Сейчас они содержат координаты относительно поля.
+=======
+Next we need to assign the correct `ball.style.left/top`. They contain field-relative coordinates now.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Картинка:
@@ -36,7 +40,11 @@
let left = event.clientX - fieldCoords.left - field.clientLeft;
```
+<<<<<<< HEAD
Значение `ball.style.left` означает "левый край элемента" (мяча). И если мы назначим такой `left` для мяча, тогда его левая граница, а не центр, будет под курсором мыши.
+=======
+Normally, `ball.style.left` means the "left edge of the element" (the ball). So if we assign that `left`, then the ball edge, not center, would be under the mouse cursor.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Нам нужно сдвинуть мяч на половину его высоты вверх и половину его ширины влево, чтобы центр мяча точно совпадал с точкой нажатия мышки.
diff --git a/2-ui/2-events/01-introduction-browser-events/07-carousel/solution.md b/2-ui/2-events/01-introduction-browser-events/07-carousel/solution.md
index c57a6d3161..83b31e1392 100644
--- a/2-ui/2-events/01-introduction-browser-events/07-carousel/solution.md
+++ b/2-ui/2-events/01-introduction-browser-events/07-carousel/solution.md
@@ -1,6 +1,10 @@
Лента изображений в разметке должна быть представлена как список `ul/li` с картинками ``.
+<<<<<<< HEAD
Нужно расположить ленту внутри `
` фиксированного размера, так чтобы в один момент была видна только нужная часть списка:
+=======
+Normally, such a ribbon is wide, but we put a fixed-size `
` around to "cut" it, so that only a part of the ribbon is visible:
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a

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 2b57154f71..6c9181a4d9 100644
--- a/2-ui/2-events/01-introduction-browser-events/article.md
+++ b/2-ui/2-events/01-introduction-browser-events/article.md
@@ -11,6 +11,7 @@
- `mousedown` / `mouseup` -- когда нажали / отжали кнопку мыши на элементе.
- `mousemove` -- при движении мыши.
+<<<<<<< HEAD
**События на элементах управления:**
- `submit` -- пользователь отправил форму `
+
+
+
+
diff --git a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseenter-mouseleave-delegation-2.view/script.js b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseenter-mouseleave-delegation-2.view/script.js
index d783d5e20e..113eb399bd 100755
--- a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseenter-mouseleave-delegation-2.view/script.js
+++ b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseenter-mouseleave-delegation-2.view/script.js
@@ -18,7 +18,7 @@ table.onmouseover = function(event) {
// ура, мы зашли на новый
currentElem = target;
- target.style.background = 'pink';
+ onEnter(currentElem);
};
@@ -39,7 +39,29 @@ table.onmouseout = function(event) {
relatedTarget = relatedTarget.parentNode;
}
+<<<<<<< HEAD
// мы действительно покинули элемент
currentElem.style.background = '';
+=======
+ // we left the
. really.
+ onLeave(currentElem);
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
currentElem = null;
};
+
+// any functions to handle entering/leaving an element
+function onEnter(elem) {
+ elem.style.background = 'pink';
+
+ // show that in textarea
+ text.value += `over -> ${currentElem.tagName}.${currentElem.className}\n`;
+ text.scrollTop = 1e6;
+}
+
+function onLeave(elem) {
+ elem.style.background = '';
+
+ // show that in textarea
+ text.value += `out <- ${elem.tagName}.${elem.className}\n`;
+ text.scrollTop = 1e6;
+}
diff --git a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseenter-mouseleave-delegation.view/script.js b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseenter-mouseleave-delegation.view/script.js
index 4700d686e2..ae633ad67d 100755
--- a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseenter-mouseleave-delegation.view/script.js
+++ b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseenter-mouseleave-delegation.view/script.js
@@ -1,13 +1,15 @@
table.onmouseover = function(event) {
let target = event.target;
target.style.background = 'pink';
- text.value += "mouseover " + target.tagName + "\n";
+
+ text.value += `over -> ${target.tagName}\n`;
text.scrollTop = text.scrollHeight;
};
table.onmouseout = function(event) {
let target = event.target;
target.style.background = '';
- text.value += "mouseout " + target.tagName + "\n";
+
+ text.value += `out <- ${target.tagName}\n`;
text.scrollTop = text.scrollHeight;
-};
\ No newline at end of file
+};
diff --git a/2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/solution.view/soccer.js b/2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/solution.view/soccer.js
index 1c1443a7e7..10ae2eeed0 100644
--- a/2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/solution.view/soccer.js
+++ b/2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/solution.view/soccer.js
@@ -7,7 +7,7 @@ document.addEventListener('mousedown', function(event) {
if (!dragElement) return;
event.preventDefault();
-
+
dragElement.ondragstart = function() {
return false;
};
@@ -19,7 +19,7 @@ document.addEventListener('mousedown', function(event) {
function onMouseUp(event) {
finishDrag();
};
-
+
function onMouseMove(event) {
moveAt(event.clientX, event.clientY);
}
@@ -31,9 +31,9 @@ document.addEventListener('mousedown', function(event) {
if(isDragging) {
return;
}
-
+
isDragging = true;
-
+
document.addEventListener('mousemove', onMouseMove);
element.addEventListener('mouseup', onMouseUp);
@@ -50,10 +50,10 @@ document.addEventListener('mousedown', function(event) {
if(!isDragging) {
return;
}
-
+
isDragging = false;
- dragElement.style.top = parseInt(dragElement.style.top) + pageYOffset + 'px';
+ dragElement.style.top = parseInt(dragElement.style.top) + window.pageYOffset + 'px';
dragElement.style.position = 'absolute';
document.removeEventListener('mousemove', onMouseMove);
@@ -113,4 +113,4 @@ document.addEventListener('mousedown', function(event) {
dragElement.style.top = newY + 'px';
}
-});
\ No newline at end of file
+});
diff --git a/2-ui/3-event-details/4-mouse-drag-and-drop/article.md b/2-ui/3-event-details/4-mouse-drag-and-drop/article.md
index 4afde91703..baf290f702 100644
--- a/2-ui/3-event-details/4-mouse-drag-and-drop/article.md
+++ b/2-ui/3-event-details/4-mouse-drag-and-drop/article.md
@@ -1,5 +1,6 @@
# Drag'n'Drop с событиями мыши
+<<<<<<< HEAD
Drag'n'Drop - отличный способ улучшить интерфейс. Захват элемента мышкой и его перенос визуально упростят что угодно: от копирования и перемещения документов (как в файловых менеджерах) до оформления заказа ("положить в корзину").
В современном стандарте HTML5 есть [раздел о Drag and Drop](https://html.spec.whatwg.org/multipage/interaction.html#dnd) - и там есть специальные события именно для Drag'n'Drop переноса, такие как `dragstart`, `dragend` и так далее.
@@ -9,11 +10,23 @@ Drag'n'Drop - отличный способ улучшить интерфейс.
Но у них есть и ограничения. Например, нельзя организовать перенос "только по горизонтали" или "только по вертикали". Также нельзя ограничить перенос внутри заданной зоны. Есть и другие интерфейсные задачи, которые такими встроенными событиями не реализуемы. Кроме того, мобильные устройства плохо их поддерживают.
Здесь мы будем рассматривать Drag'n'Drop при помощи событий мыши.
+=======
+Drag'n'Drop is a great interface solution. Taking something and dragging and dropping it is a clear and simple way to do many things, from copying and moving documents (as in file managers) to ordering (dropping items into a cart).
+
+In the modern HTML standard there's a [section about Drag and Drop](https://html.spec.whatwg.org/multipage/interaction.html#dnd) with special events such as `dragstart`, `dragend`, and so on.
+
+These events allow us to support special kinds of drag'n'drop, such as handling dragging a file from OS file-manager and dropping it into the browser window. Then JavaScript can access the contents of such files.
+
+But native Drag Events also have limitations. For instance, we can't prevent dragging from a certain area. Also we can't make the dragging "horizontal" or "vertical" only. And there are many other drag'n'drop tasks that can't be done using them. Also, mobile device support for such events is very weak.
+
+So here we'll see how to implement Drag'n'Drop using mouse events.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
## Алгоритм Drag'n'Drop
Базовый алгоритм Drag'n'Drop выглядит так:
+<<<<<<< HEAD
1. При `mousedown` - готовим элемент к перемещению, если необходимо (например, создаём его копию).
2. Затем при `mousemove` передвигаем элемент на новые координаты путём смены `left/top` и `position:absolute`.
3. При `mouseup` - остановить перенос элемента и произвести все действия, связанные с окончанием Drag'n'Drop.
@@ -34,6 +47,25 @@ ball.onmousedown = function(event) { // (1) отследить нажатие
// и установим абсолютно спозиционированный мяч под курсор
moveAt(event.pageX, event.pageY);
+=======
+1. On `mousedown` - prepare the element for moving, if needed (maybe create a clone of it, add a class to it or whatever).
+2. Then on `mousemove` move it by changing `left/top` with `position:absolute`.
+3. On `mouseup` - perform all actions related to finishing the drag'n'drop.
+
+These are the basics. Later we'll see how to other features, such as highlighting current underlying elements while we drag over them.
+
+Here's the implementation of dragging a ball:
+
+```js
+ball.onmousedown = function(event) {
+ // (1) prepare to moving: make absolute and on top by z-index
+ ball.style.position = 'absolute';
+ ball.style.zIndex = 1000;
+
+ // move it out of any current parents directly into body
+ // to make it positioned relative to the body
+ document.body.append(ball);
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
// передвинуть мяч под координаты курсора
// и сдвинуть на половину ширины/высоты для центрирования
@@ -42,14 +74,24 @@ ball.onmousedown = function(event) { // (1) отследить нажатие
ball.style.top = pageY - ball.offsetHeight / 2 + 'px';
}
+ // move our absolutely positioned ball under the pointer
+ moveAt(event.pageX, event.pageY);
+
function onMouseMove(event) {
moveAt(event.pageX, event.pageY);
}
+<<<<<<< HEAD
// (3) перемещать по экрану
document.addEventListener('mousemove', onMouseMove);
// (4) положить мяч, удалить более ненужные обработчики событий
+=======
+ // (2) move the ball on mousemove
+ document.addEventListener('mousemove', onMouseMove);
+
+ // (3) drop the ball, remove unneeded handlers
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
ball.onmouseup = function() {
document.removeEventListener('mousemove', onMouseMove);
ball.onmouseup = null;
@@ -65,10 +107,17 @@ ball.onmousedown = function(event) { // (1) отследить нажатие
[iframe src="ball" height=230]
+<<<<<<< HEAD
Попробуйте перенести мяч мышкой и вы увидите описанное поведение.
```
Всё потому, что браузер имеет свой собственный Drag'n'Drop, который автоматически запускается и вступает в конфликт с нашим. Это происходит именно для картинок и некоторых других элементов.
+=======
+Try to drag'n'drop with the mouse and you'll see such behavior.
+```
+
+That's because the browser has its own drag'n'drop support for images and some other elements. It runs automatically and conflicts with ours.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Его нужно отключить:
@@ -281,7 +330,11 @@ function onMouseMove(event) {
}
```
+<<<<<<< HEAD
В приведённом ниже примере, когда мяч перетаскивается через футбольные ворота, ворота подсвечиваются.
+=======
+In the example below when the ball is dragged over the soccer goal, the goal is highlighted.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
[codetabs height=250 src="ball4"]
@@ -305,4 +358,8 @@ function onMouseMove(event) {
- Можно использовать делегирование событий для `mousedown/up`. Один обработчик событий на большой зоне, который проверяет `event.target`, может управлять Drag'n'Drop для сотен элементов.
- И так далее.
+<<<<<<< HEAD
Существуют фреймворки, которые строят архитектуру поверх этого алгоритма, создавая такие классы, как `DragZone`, `Droppable`, `Draggable`. Большинство из них делают вещи, аналогичные описанным выше. Вы можете и создать вашу собственную реализацию переноса, как видите, это достаточно просто, возможно, проще, чем адаптация чего-то готового.
+=======
+There are frameworks that build architecture over it: `DragZone`, `Droppable`, `Draggable` and other classes. Most of them do the similar stuff to what's described above, so it should be easy to understand them now. Or roll your own, as you can see that that's easy enough to do, sometimes easier than adapting a third-party solution.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
diff --git a/2-ui/3-event-details/4-mouse-drag-and-drop/ball.view/index.html b/2-ui/3-event-details/4-mouse-drag-and-drop/ball.view/index.html
index acb990bec0..34c1f11103 100644
--- a/2-ui/3-event-details/4-mouse-drag-and-drop/ball.view/index.html
+++ b/2-ui/3-event-details/4-mouse-drag-and-drop/ball.view/index.html
@@ -13,16 +13,13 @@
+
+
+
diff --git a/2-ui/3-event-details/6-pointer-events/ball.view/index.html b/2-ui/3-event-details/6-pointer-events/ball.view/index.html
new file mode 100644
index 0000000000..8bbef8f631
--- /dev/null
+++ b/2-ui/3-event-details/6-pointer-events/ball.view/index.html
@@ -0,0 +1,30 @@
+
+
+
+
+
diff --git a/2-ui/3-event-details/6-pointer-events/slider.view/style.css b/2-ui/3-event-details/6-pointer-events/slider.view/style.css
new file mode 100644
index 0000000000..9b3d3b82d4
--- /dev/null
+++ b/2-ui/3-event-details/6-pointer-events/slider.view/style.css
@@ -0,0 +1,19 @@
+.slider {
+ border-radius: 5px;
+ background: #E0E0E0;
+ background: linear-gradient(left top, #E0E0E0, #EEEEEE);
+ width: 310px;
+ height: 15px;
+ margin: 5px;
+}
+
+.thumb {
+ width: 10px;
+ height: 25px;
+ border-radius: 3px;
+ position: relative;
+ left: 10px;
+ top: -5px;
+ background: blue;
+ cursor: pointer;
+}
diff --git a/2-ui/3-event-details/5-keyboard-events/2-check-sync-keydown/solution.md b/2-ui/3-event-details/7-keyboard-events/2-check-sync-keydown/solution.md
similarity index 100%
rename from 2-ui/3-event-details/5-keyboard-events/2-check-sync-keydown/solution.md
rename to 2-ui/3-event-details/7-keyboard-events/2-check-sync-keydown/solution.md
diff --git a/2-ui/3-event-details/5-keyboard-events/2-check-sync-keydown/solution.view/index.html b/2-ui/3-event-details/7-keyboard-events/2-check-sync-keydown/solution.view/index.html
similarity index 100%
rename from 2-ui/3-event-details/5-keyboard-events/2-check-sync-keydown/solution.view/index.html
rename to 2-ui/3-event-details/7-keyboard-events/2-check-sync-keydown/solution.view/index.html
diff --git a/2-ui/3-event-details/5-keyboard-events/2-check-sync-keydown/task.md b/2-ui/3-event-details/7-keyboard-events/2-check-sync-keydown/task.md
similarity index 100%
rename from 2-ui/3-event-details/5-keyboard-events/2-check-sync-keydown/task.md
rename to 2-ui/3-event-details/7-keyboard-events/2-check-sync-keydown/task.md
diff --git a/2-ui/3-event-details/5-keyboard-events/article.md b/2-ui/3-event-details/7-keyboard-events/article.md
similarity index 100%
rename from 2-ui/3-event-details/5-keyboard-events/article.md
rename to 2-ui/3-event-details/7-keyboard-events/article.md
diff --git a/2-ui/3-event-details/7-keyboard-events/german-layout.svg b/2-ui/3-event-details/7-keyboard-events/german-layout.svg
new file mode 100644
index 0000000000..8a880e8e03
--- /dev/null
+++ b/2-ui/3-event-details/7-keyboard-events/german-layout.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/2-ui/3-event-details/5-keyboard-events/keyboard-dump.view/index.html b/2-ui/3-event-details/7-keyboard-events/keyboard-dump.view/index.html
similarity index 100%
rename from 2-ui/3-event-details/5-keyboard-events/keyboard-dump.view/index.html
rename to 2-ui/3-event-details/7-keyboard-events/keyboard-dump.view/index.html
diff --git a/2-ui/3-event-details/5-keyboard-events/keyboard-dump.view/script.js b/2-ui/3-event-details/7-keyboard-events/keyboard-dump.view/script.js
similarity index 100%
rename from 2-ui/3-event-details/5-keyboard-events/keyboard-dump.view/script.js
rename to 2-ui/3-event-details/7-keyboard-events/keyboard-dump.view/script.js
diff --git a/2-ui/3-event-details/5-keyboard-events/keyboard-dump.view/style.css b/2-ui/3-event-details/7-keyboard-events/keyboard-dump.view/style.css
similarity index 100%
rename from 2-ui/3-event-details/5-keyboard-events/keyboard-dump.view/style.css
rename to 2-ui/3-event-details/7-keyboard-events/keyboard-dump.view/style.css
diff --git a/2-ui/3-event-details/5-keyboard-events/us-layout.svg b/2-ui/3-event-details/7-keyboard-events/us-layout.svg
similarity index 100%
rename from 2-ui/3-event-details/5-keyboard-events/us-layout.svg
rename to 2-ui/3-event-details/7-keyboard-events/us-layout.svg
diff --git a/2-ui/3-event-details/8-onscroll/1-endless-page/solution.md b/2-ui/3-event-details/8-onscroll/1-endless-page/solution.md
index 14646284ee..0f5817ce9c 100644
--- a/2-ui/3-event-details/8-onscroll/1-endless-page/solution.md
+++ b/2-ui/3-event-details/8-onscroll/1-endless-page/solution.md
@@ -55,11 +55,19 @@ function populate() {
// нижняя граница документа
let windowRelativeBottom = document.documentElement.getBoundingClientRect().bottom;
+<<<<<<< HEAD
// если пользователь прокрутил достаточно далеко (< 100px до конца)
if (windowRelativeBottom < document.documentElement.clientHeight + 100) {
// добавим больше данных
document.body.insertAdjacentHTML("beforeend", `
Дата: ${new Date()}
`);
}
+=======
+ // if the user hasn't scrolled far enough (>100px to the end)
+ if (windowRelativeBottom > document.documentElement.clientHeight + 100) break;
+
+ // let's add more data
+ document.body.insertAdjacentHTML("beforeend", `
* Достаточно, чтобы верхний или нижний край элемента был виден
*/
function isVisible(elem) {
+<<<<<<< HEAD
// ...ваш код...
+=======
+ // todo: your code
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
}
function showVisible() {
diff --git a/2-ui/3-event-details/8-onscroll/article.md b/2-ui/3-event-details/8-onscroll/article.md
index 59ff73df7e..7afe3cb831 100644
--- a/2-ui/3-event-details/8-onscroll/article.md
+++ b/2-ui/3-event-details/8-onscroll/article.md
@@ -1,6 +1,10 @@
# Прокрутка
+<<<<<<< HEAD
Событие прокрутки `scroll` позволяет реагировать на прокрутку страницы или элемента. Есть много хороших вещей, которые при этом можно сделать.
+=======
+The `scroll` event allows reacting to a page or element scrolling. There are quite a few good things we can do here.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Например:
- Показать/скрыть дополнительные элементы управления или информацию, основываясь на том, в какой части документа находится пользователь.
@@ -10,7 +14,7 @@
```js autorun
window.addEventListener('scroll', function() {
- document.getElementById('showScroll').innerHTML = pageYOffset + 'px';
+ document.getElementById('showScroll').innerHTML = window.pageYOffset + 'px';
});
```
@@ -34,4 +38,8 @@ window.addEventListener('scroll', function() {
Способов инициировать прокрутку много, поэтому более надёжный способ -- использовать CSS, свойство `overflow`.
+<<<<<<< HEAD
Вот несколько задач, которые вы можете решить или просмотреть, чтобы увидеть применение `onscroll`.
+=======
+Here are few tasks that you can solve or look through to see applications of `onscroll`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
diff --git a/2-ui/4-forms-controls/1-form-elements/1-add-select-option/task.md b/2-ui/4-forms-controls/1-form-elements/1-add-select-option/task.md
index ab5d03393f..ac5e5b8f76 100644
--- a/2-ui/4-forms-controls/1-form-elements/1-add-select-option/task.md
+++ b/2-ui/4-forms-controls/1-form-elements/1-add-select-option/task.md
@@ -15,6 +15,14 @@ importance: 5
Используя JavaScript:
+<<<<<<< HEAD
1. Выведите значение и текст выбранного пункта.
2. Добавьте пункт: ``.
3. Сделайте его выбранным.
+=======
+1. Show the value and the text of the selected option.
+2. Add an option: ``.
+3. Make it selected.
+
+Note, if you've done everything right, your alert should show `blues`.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
diff --git a/2-ui/4-forms-controls/1-form-elements/article.md b/2-ui/4-forms-controls/1-form-elements/article.md
index 8c37069a82..6cadace6b7 100644
--- a/2-ui/4-forms-controls/1-form-elements/article.md
+++ b/2-ui/4-forms-controls/1-form-elements/article.md
@@ -124,7 +124,11 @@ alert(ageElems[0]); // [object HTMLInputElement]
## Обратная ссылка: element.form
+<<<<<<< HEAD
Для любого элемента форма доступна через `element.form`. Так что форма ссылается на все элементы, а эти элементы ссылаются на форму.
+=======
+For any element, the form is available as `element.form`. So a form references all elements, and elements reference the form.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Вот иллюстрация:
diff --git a/2-ui/4-forms-controls/2-focus-blur/article.md b/2-ui/4-forms-controls/2-focus-blur/article.md
index a36417cb81..cf9899b0fa 100644
--- a/2-ui/4-forms-controls/2-focus-blur/article.md
+++ b/2-ui/4-forms-controls/2-focus-blur/article.md
@@ -1,6 +1,10 @@
# Фокусировка: focus/blur
+<<<<<<< HEAD
Элемент получает фокус, когда пользователь кликает по нему или использует клавишу `key:Tab`. Также существует HTML-атрибут `autofocus`, который устанавливает фокус на элемент, когда страница загружается. Есть и другие способы получения фокуса, о них - далее.
+=======
+An element receives the focus when the user either clicks on it or uses the `key:Tab` key on the keyboard. There's also an `autofocus` HTML attribute that puts the focus onto an element by default when a page loads and other means of getting the focus.
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
Фокусировка обычно означает: "приготовься к вводу данных на этом элементе", это хороший момент, чтобы инициализовать или загрузить что-нибудь.
@@ -18,8 +22,13 @@
В примере ниже:
+<<<<<<< HEAD
- Обработчик `blur` проверяет, введён ли email, и если нет -- показывает ошибку.
- Обработчик `focus` скрывает это сообщение об ошибке (в момент потери фокуса проверка повторится):
+=======
+- The `blur` handler checks if the field has an email entered, and if not -- shows an error.
+- The `focus` handler hides the error message (on `blur` it will be checked again):
+>>>>>>> f830bc5d9454d85829e011d914f215eb5896579a
```html run autorun height=60