diff --git a/modules/10-basics/10-hello-world/ru/EXERCISE.md b/modules/10-basics/10-hello-world/ru/EXERCISE.md new file mode 100644 index 0000000..55762e3 --- /dev/null +++ b/modules/10-basics/10-hello-world/ru/EXERCISE.md @@ -0,0 +1,7 @@ +Наберите в редакторе код из задания символ в символ и нажмите «Проверить». + +```javascript +console.log('Hello, World!'); +``` + +Внимание: если вы напишете `heLLo, woRld!` вместо `Hello, World!`, то это будет считаться другим текстом, потому что заглавные и строчные буквы — это разные символы. Размер буквы называют *регистром*, и говорят: *регистр — важен!* Это касается почти всего в коде, поэтому привыкайте всегда обращать внимание на регистр. diff --git a/modules/10-basics/10-hello-world/ru/README.md b/modules/10-basics/10-hello-world/ru/README.md new file mode 100644 index 0000000..5a88708 --- /dev/null +++ b/modules/10-basics/10-hello-world/ru/README.md @@ -0,0 +1,9 @@ +Изучение нового языка программирования традиционно начинается с 'Hello, World!'. Это простая программа, которая выводит приветствие на экран и заодно знакомит с новым языком — его синтаксисом и структурой программы. Этой традиции уже больше сорока лет, поэтому и мы не будем ее нарушать — в первом же уроке напишем программу `Hello, World!`. + +Эта программа будет выводить на экран текст: + +
+ Hello, World! ++ +Чтобы вывести что-то на экран, нужно дать компьютеру специальную команду. В языке JavaScript такая команда — `console.log()`. diff --git a/modules/10-basics/10-hello-world/ru/data.yml b/modules/10-basics/10-hello-world/ru/data.yml new file mode 100644 index 0000000..1a060c7 --- /dev/null +++ b/modules/10-basics/10-hello-world/ru/data.yml @@ -0,0 +1,5 @@ +name: Привет, Мир! +tips: + - > + [Немного о 'Hello, + World!'](https://ru.hexlet.io/blog/posts/moy-chelovek-menya-ponimaet-istoriya-frazy-hello-world-i-ee-analogov) diff --git a/modules/10-basics/20-comments/ru/EXERCISE.md b/modules/10-basics/20-comments/ru/EXERCISE.md new file mode 100644 index 0000000..b326c80 --- /dev/null +++ b/modules/10-basics/20-comments/ru/EXERCISE.md @@ -0,0 +1 @@ +Создайте однострочный комментарий с текстом: `You know nothing, Jon Snow!`. diff --git a/modules/10-basics/20-comments/ru/README.md b/modules/10-basics/20-comments/ru/README.md new file mode 100644 index 0000000..fadb17a --- /dev/null +++ b/modules/10-basics/20-comments/ru/README.md @@ -0,0 +1,42 @@ + +Кроме кода, в файлах с исходным кодом могут находиться комментарии. Это текст, который не является частью программы и нужен программистам для пометок. С их помощью добавляют пояснения, как работает код, какие здесь ошибки нужно поправить или не забыть что-то добавить позже. + +```javascript +// Удалить строку ниже после реализации задачи по регистрации +console.log(10); +``` + +Комментарии в JavaScript бывают двух видов: + +## Однострочные комментарии + +*Однострочные комментарии* начинаются с `//`. После этих двух символов может следовать любой текст, вся строчка не будет анализироваться и исполняться. + +Комментарий может занимать всю строчку. Если одной строчки мало, то создаются несколько комментариев: + +```javascript +// For Winterfell! +// For Lanisters! +``` + +Комментарий может находиться на строчке после какого-нибудь кода: + +```javascript +console.log('I am the King'); // For Lannisters! +``` + +## Многострочные комментарии + +*Многострочные комментарии* начинаются с `/*` и заканчиваются на `*/`. + +```javascript +/* + The night is dark and + full of terrors. +*/ +console.log('I am the King'); +``` + +https://replit.com/@hexlet/helloworld + +Такие комментарии, обычно, используют для документирования кода, например, функций. diff --git a/modules/10-basics/20-comments/ru/data.yml b/modules/10-basics/20-comments/ru/data.yml new file mode 100644 index 0000000..c3d969c --- /dev/null +++ b/modules/10-basics/20-comments/ru/data.yml @@ -0,0 +1,22 @@ +name: Комментарии +tips: + - | + [Подробнее о комментариях](https://www.w3schools.com/js/js_comments.asp) +definitions: + - name: Комментарий + description: > + текст в коде программы, который не влияет на функциональность и + добавляется программистами для себя и своих коллег. + + + `// однострочный комментарий` + + + ``` + + /* + многострочный комментарий + многострочный комментарий + */ + + ``` diff --git a/modules/10-basics/40-instructions/ru/EXERCISE.md b/modules/10-basics/40-instructions/ru/EXERCISE.md new file mode 100644 index 0000000..f49eca8 --- /dev/null +++ b/modules/10-basics/40-instructions/ru/EXERCISE.md @@ -0,0 +1,9 @@ +Выведите на экран друг за другом три имени: *Robert*, *Stannis*, *Renly*. В результате на экране должно отобразиться: + +
+Robert +Stannis +Renly ++ +Для каждого имени используйте свой собственный вызов `console.log()`. diff --git a/modules/10-basics/40-instructions/ru/README.md b/modules/10-basics/40-instructions/ru/README.md new file mode 100644 index 0000000..0c39d45 --- /dev/null +++ b/modules/10-basics/40-instructions/ru/README.md @@ -0,0 +1,27 @@ +Инструкция — это команда для компьютера выполнить что-то. Код на JavaScript — это набор инструкций, которые, как правило, отделяются друг от друга символом `;`. + +Вот пример кода с двумя инструкциями. + +```javascript +console.log('Mother of Dragons.'); +console.log('Dracarys!'); +``` + +https://replit.com/@hexlet/js-basics-instructions + +При запуске этого кода, на экран последовательно выводятся два предложения: + +
+Mother of Dragons. +Dracarys! ++ +Теоретически, инструкции можно написать друг за другом без переноса на новую строчку: + +```javascript +console.log('Mother of Dragons.'); console.log('Drakarys!'); +``` + +Результат на экране будет таким же, но такой код неудобен для чтения, поэтому инструкции располагают друг под другом. + +Почему это важно знать? Инструкция — это единица исполнения. Интерпретатор, программа которая запускает код на JavaScript, выполняет инструкции строго по очереди. И мы, как разработчики, должны понимать этот порядок и уметь мысленно разделять программу на независимые части, удобные для анализа. diff --git a/modules/10-basics/40-instructions/ru/data.yml b/modules/10-basics/40-instructions/ru/data.yml new file mode 100644 index 0000000..84b236e --- /dev/null +++ b/modules/10-basics/40-instructions/ru/data.yml @@ -0,0 +1,15 @@ +name: Инструкции (Statements) +tips: + - | + [Немного об интерпретаторах](https://ru.wikipedia.org/wiki/Интерпретатор) + - > + [Инструкции и объявления по + категориям](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements) +definitions: + - name: Интерпретатор + description: | + программа, выполняющая код на JavaScript. + - name: Инструкция (statement) + description: > + команда для компьютера, написанная на языке программирования. Код на + JavaScript — это набор инструкций, разделенных (чаще всего) символом `;`. diff --git a/modules/10-basics/45-testing/ru/EXERCISE.md b/modules/10-basics/45-testing/ru/EXERCISE.md new file mode 100644 index 0000000..806aa22 --- /dev/null +++ b/modules/10-basics/45-testing/ru/EXERCISE.md @@ -0,0 +1,7 @@ +Просто тренировка. Выведите на экран число 9780262531962. + +
+9780262531962 ++ +Поэкспериментируйте с выводом. Передайте туда другое число или строку. Посмотрите на ответ системы, попробуйте его перевести и понять. diff --git a/modules/10-basics/45-testing/ru/README.md b/modules/10-basics/45-testing/ru/README.md new file mode 100644 index 0000000..6e86eb8 --- /dev/null +++ b/modules/10-basics/45-testing/ru/README.md @@ -0,0 +1,35 @@ + +Сайт автоматически проверяет ваши решения. Как это работает? + +В самом простом случае, система просто запускает ваш код и смотрит на то, что вывелось на экран. А потом сверяет с тем, что мы «ожидали» по заданию. + +В следующих, более сложных уроках, вы будете писать функции — некие мини-программы, принимающие информацию из внешнего мира и производящие какие-то операции. Проверка ваших решений в таких случаях выглядит немного сложнее: система запускает ваше решение и передаёт какую-то информацию. Система также знает — «ожидает» — какой именно ответ должна дать правильная функция при таких входных данных. + +Например, если ваша задача — написать функцию сложения двух чисел, то проверочная система будет передавать ей разные комбинации чисел и сверять ответ вашей функции с реальными суммами. Если во всех случаях ответы совпадут, то решение считается верным. + +Такой подход называется тестированием, и он используется в реальной повседневной разработке. Обычно программист сначала пишет тест — проверочную программу, а потом уже ту программу, которую хотел написать. В процессе он постоянно запускает тесты и смотрит, приблизился ли он к решению. + +Именно поэтому наш сайт говорит «Тесты пройдены», когда вы правильно решили задачу. + +Вот простой пример: в одном из будущих уроков вам нужно будет написать функцию, которая производит вычисления и выдаёт ответ. Предположим, вы допустили небольшую ошибку, и функция выдала неправильное число. Система ответит примерно так: + +
+ ● test + + expect(received).toBe(expected) // Object.is equality + + Expected value to be: + "Hello, World!" + Received: + "ello, World!" ++ +Expected – ожидаемое значение, а Received, то которое выдал ваш код. + +Кроме наших тестов, будет крайне полезно экспериментировать с кодом в консоли [браузера](https://developer.mozilla.org/en-US/docs/Tools/Browser_Console). В любой ситуации, когда вы недопоняли, или хотите попробовать разные варианты использования, смело открывайте консоль и вводите туда код. Идеально, если вы выполните самостоятельно весь код, который присутствует в уроках. Кроме консоли, полезно использовать сервис [repl.it](https://repl.it/languages/javascript). + +--- + +Иногда в процессе решения будет казаться, что вы сделали все правильно, но система "капризничает" и не принимает решение. Подобное поведение практически исключено. Нерабочие тесты просто не могут попасть на сайт, они автоматически запускаются после каждого изменения. В подавляющем большинстве таких случаев, (а все наши проекты в сумме провели миллионы проверок за много лет), ошибка содержится в коде решения. Она может быть очень незаметной, вместо английской буквы случайно ввели русскую, вместо верхнего регистра использовали нижний или забыли вывести запятую. Другие случаи сложнее. Возможно ваше решение работает для одного набора входных данных, но не работает для другого. Поэтому всегда внимательно читайте условие задачи и вывод тестов. Там почти наверняка есть указание на ошибку. + +Однако, если вы уверены в ошибке или нашли какую-то неточность, то вы всегда можете указать на нее. В конце каждой теории есть ссылка на содержимое урока на гитхабе (этот проект полностью открытый!). Перейдя туда, вы можете написать issue, посмотреть содержимое тестов (там видно, как вызывается ваш код) и даже отправить pullrequest. Если для вас это пока темный лес, то подключитесь в наше сообщество [Telegram] (https://t.me/hexletcommunity), там в канале *Обратная связь* мы всегда поможем. diff --git a/modules/10-basics/45-testing/ru/data.yml b/modules/10-basics/45-testing/ru/data.yml new file mode 100644 index 0000000..708a386 --- /dev/null +++ b/modules/10-basics/45-testing/ru/data.yml @@ -0,0 +1,11 @@ +name: Как мы проверяем ваши решения +definitions: + - name: Тесты + description: > + специальный код, проверяющий программы на корректность, сверяя правильный + результат с реальным. +tips: + - | + [TDD](https://ru.wikipedia.org/wiki/Разработка_через_тестирование) + - | + [Сообщество Хекслета в Telegram](https://t.me/hexletcommunity) diff --git a/modules/10-basics/50-syntax-errors/ru/EXERCISE.md b/modules/10-basics/50-syntax-errors/ru/EXERCISE.md new file mode 100644 index 0000000..aff6b2f --- /dev/null +++ b/modules/10-basics/50-syntax-errors/ru/EXERCISE.md @@ -0,0 +1,4 @@ + +Это задание не связано с уроком напрямую. Но будет полезным потренироваться с выводом на экран. + +Выведите на экран *What Is Dead May Never Die* diff --git a/modules/10-basics/50-syntax-errors/ru/README.md b/modules/10-basics/50-syntax-errors/ru/README.md new file mode 100644 index 0000000..c6e7f16 --- /dev/null +++ b/modules/10-basics/50-syntax-errors/ru/README.md @@ -0,0 +1,18 @@ + +Если программа на JavaScript написана синтаксически некорректно, то интерпретатор выводит на экран соответствующее сообщение, а также указание на файл и строчку в нём, где, по его мнению, произошла ошибка. *Синтаксическая ошибка* возникает в том случае, когда код был записан с нарушением грамматических правил. В человеческих языках грамматика важна, но текст с ошибками чаще всего можно понять и прочитать. В программировании всё строго. Любое мельчайшее нарушение, и программа даже не запустится. Примером может быть забытая `;`, неправильно расставленные скобки и другие детали. + +Вот пример кода с синтаксической ошибкой: + +```javascript +console.log('Hodor' +``` + +Если запустить код выше, то мы увидим следующее сообщение: `SyntaxError: missing ) after argument list`, а также указание на строку и файл, где возникла эта ошибка. Подобные синтаксические ошибки в JavaScript относятся к разряду SyntaxError. + +*По техническим причинам, такой код, запущенный на https://code-basics.com не укажет на строку и файл. Проверить этот вывод можно на https://repl.it* + +https://replit.com/@hexlet/js-basics-syntax-errors + +С одной стороны, ошибки SyntaxError — самые простые, потому что они связаны исключительно с грамматическими правилами написания кода, а не с самим смыслом кода. Их легко исправить: нужно лишь найти нарушение в записи. + +С другой стороны, интерпретатор не всегда может чётко указать на это нарушение. Поэтому бывает, что забытую скобку нужно поставить не туда, куда указывает сообщение об ошибке. diff --git a/modules/10-basics/50-syntax-errors/ru/data.yml b/modules/10-basics/50-syntax-errors/ru/data.yml new file mode 100644 index 0000000..4321094 --- /dev/null +++ b/modules/10-basics/50-syntax-errors/ru/data.yml @@ -0,0 +1,11 @@ +name: Синтаксические ошибки +tips: + - | + [Ошибки в JavaScript](https://habr.com/ru/post/249525/) +definitions: + - name: Синтаксическая ошибка + description: нарушение грамматических правил языка программирования. + - name: SyntaxError (ошибка парсинга) + description: >- + тип ошибок в JavaScript, возникающих при наличии синтаксических ошибок в + коде. diff --git a/modules/20-arithmetics/20-basic/ru/EXERCISE.md b/modules/20-arithmetics/20-basic/ru/EXERCISE.md new file mode 100644 index 0000000..c6e757d --- /dev/null +++ b/modules/20-arithmetics/20-basic/ru/EXERCISE.md @@ -0,0 +1,2 @@ + +Выведите на экран результат деления числа `81` на `9`. diff --git a/modules/20-arithmetics/20-basic/ru/README.md b/modules/20-arithmetics/20-basic/ru/README.md new file mode 100644 index 0000000..a002fe9 --- /dev/null +++ b/modules/20-arithmetics/20-basic/ru/README.md @@ -0,0 +1,44 @@ +На базовом уровне компьютеры оперируют только числами. Даже в прикладных программах на высокоуровневых языках внутри много чисел и операций над ними. К счастью, для старта достаточно знать обычную арифметику — с нее и начнем. + +Для сложения двух чисел в математике мы пишем, например, `3 + 4`. В программировании — то же самое. Вот программа, складывающая два числа: + +```javascript +// Не забываем точку с запятой в конце, +// так как каждая строчка в коде - инструкция +3 + 4; +``` + +Инструкция `3 + 4;` заставит компьютер сложить числа и узнать результат. Если запустить эту программу, то ничего не произойдет. А если быть точными, то компьютер вычислит сумму, но на этом всё. Результат сложения никак не используется, и такая программа не представляет никакого интереса. Нам нужно попросить компьютер сложить `3 + 4` **и** дать команду сделать что-то с результатом. Например, вывести его на экран: + +```javascript +// Сначала вычисляется сумма, +// затем она передается в функцию печати +console.log(3 + 4); +``` + +После запуска на экране появится результат: + +
+7 ++ +Кроме сложения, доступны следующие операции: + +* `*` — умножение +* `/` — деление +* `-` — вычитание +* `%` — [остаток от деления](https://ru.wikipedia.org/wiki/Деление_с_остатком) +* `**` — возведение в степень + +Теперь давайте выведем на экран результат деления, а потом результат возведения в степень: + +```javascript +console.log(8 / 2); // => 4 +console.log(3 ** 2); // => 9 +``` + +https://replit.com/@hexlet/js-basics-arithmetics-basics + +Иногда для удобства мы будем показывать в комментариях результат запуска строчек кода, вот так: `=> РЕЗУЛЬТАТ`. Например, `// => 4`. + +Первая инструкция выведет на экран `4` (потому что 8 / 2 это 4), а вторая инструкция выведет на экран 9 (потому что 32 это 9). diff --git a/modules/20-arithmetics/20-basic/ru/data.yml b/modules/20-arithmetics/20-basic/ru/data.yml new file mode 100644 index 0000000..8b8fbf2 --- /dev/null +++ b/modules/20-arithmetics/20-basic/ru/data.yml @@ -0,0 +1,19 @@ +name: Арифметические операции +tips: + - > + Всегда отбивайте арифметические операторы пробелами от самих чисел + (операндов) – это хороший стиль программирования. Поэтому в наших примерах + `console.log(3 + 4)`, а не `console.log(3+4)`. + - > + Деление на ноль — это `Infinity` (бесконечность). Мы разберёмся с тем, что + это значит, в будущих уроках. + - > + [Арифметические + операции](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators#arithmetic_operators) + - | + [Деление с остатком](https://ru.wikipedia.org/wiki/Деление_с_остатком) +definitions: + - name: Инструкция + description: > + наименьшая автономная часть языка программирования; команда или набор + команд. Программа обычно представляет собой последовательность инструкций. diff --git a/modules/20-arithmetics/25-operator/ru/EXERCISE.md b/modules/20-arithmetics/25-operator/ru/EXERCISE.md new file mode 100644 index 0000000..003cfc9 --- /dev/null +++ b/modules/20-arithmetics/25-operator/ru/EXERCISE.md @@ -0,0 +1 @@ +Напишите программу, которая посчитает разность между числами `6` и `-81` и выведет ответ на экран. diff --git a/modules/20-arithmetics/25-operator/ru/README.md b/modules/20-arithmetics/25-operator/ru/README.md new file mode 100644 index 0000000..105580f --- /dev/null +++ b/modules/20-arithmetics/25-operator/ru/README.md @@ -0,0 +1,22 @@ + +Перед тем как двигаться дальше, разберем базовую терминологию. Знак операции, такой как `+`, называют **оператором**. Операторы выполняют операции над определенными значениями, которые называются **операндами**. Сами операторы, обычно, представлены одним или несколькими символами. Реже словом. Подавляющее большинство операторов соответствуют математическим операциям. + +```javascript +console.log(8 + 2); +``` + +https://replit.com/@hexlet/js-basics-arithmetics-operator + +В этом примере `+` — это **оператор**, а числа `8` и `2` — это **операнды**. + +В случае сложения у нас есть два операнда: один слева, другой справа от знака `+`. Операции, которые требуют наличия двух операндов, называются **бинарными**. Если пропустить хотя бы один операнд, например, `3 + ;`, то программа завершится с синтаксической ошибкой. + +Операции (не операторы) бывают не только бинарными, но и унарными (с одним операндом), и даже тернарными (с тремя операндами)! Причем операторы могут выглядеть одинаково, но обозначать разные операции. + + ```javascript + console.log(-3); // => -3 + ``` + +Выше пример применения унарной операции к числу `3`. Оператор минус перед тройкой говорит интерпретатору взять число `3` и найти противоположное, то есть `-3`. + +Это немного может сбить с толку, потому что `-3` — это одновременно и число само по себе, и оператор с операндом, но у языков программирования такая структура. diff --git a/modules/20-arithmetics/25-operator/ru/data.yml b/modules/20-arithmetics/25-operator/ru/data.yml new file mode 100644 index 0000000..35a6a3b --- /dev/null +++ b/modules/20-arithmetics/25-operator/ru/data.yml @@ -0,0 +1,14 @@ +name: Операторы +tips: + - > + [Операторы в + JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators) +definitions: + - name: Арифметическая операция + description: сложение, вычитание, умножение и деление. + - name: Унарная операция + description: >- + операция с одним операндом. Например, `-3` — унарная операция для + получения числа, противоположного числу три. + - name: Бинарная операция + description: операция с двумя операндами. Например, `3 + 9`. diff --git a/modules/20-arithmetics/27-commutativity/ru/EXERCISE.md b/modules/20-arithmetics/27-commutativity/ru/EXERCISE.md new file mode 100644 index 0000000..c3c76d8 --- /dev/null +++ b/modules/20-arithmetics/27-commutativity/ru/EXERCISE.md @@ -0,0 +1,2 @@ + +Напишите программу, которая считает и выводит последовательно на экран значения следующих математических выражений: «3 в степени 5» и «-8 разделить на -4». diff --git a/modules/20-arithmetics/27-commutativity/ru/README.md b/modules/20-arithmetics/27-commutativity/ru/README.md new file mode 100644 index 0000000..0103e66 --- /dev/null +++ b/modules/20-arithmetics/27-commutativity/ru/README.md @@ -0,0 +1,7 @@ +Мы все помним со школы: «от перемены мест слагаемых сумма не меняется». Это один из базовых и интуитивно понятных законов арифметики, он называется **коммутативным законом**. + +Бинарная операция считается коммутативной, если поменяв местами операнды, вы получаете тот же самый результат. Очевидно, что сложение - коммутативная операция: *3 + 2 = 2 + 3*. + +А вот является ли коммутативной операция вычитания? Конечно, нет: *2 - 3 ≠ 3 - 2*. В программировании этот закон работает точно так же, как в арифметике. + +Более того, большинство операций, с которыми мы будем сталкиваться в реальной жизни, не являются коммутативными. Отсюда вывод: всегда обращайте внимание на порядок того, с чем работаете. diff --git a/modules/20-arithmetics/27-commutativity/ru/data.yml b/modules/20-arithmetics/27-commutativity/ru/data.yml new file mode 100644 index 0000000..ba4caf0 --- /dev/null +++ b/modules/20-arithmetics/27-commutativity/ru/data.yml @@ -0,0 +1,11 @@ +name: Коммутативная операция +tips: + - > + [Подробнее про + коммутативность](https://ru.wikipedia.org/wiki/Коммутативность) +definitions: + - name: Коммутативность + description: > + свойство операции, когда изменение порядка операндов не влияет на + результат. Например, сложение — коммутативная операция: от перемены мест + слагаемых сумма не меняется. diff --git a/modules/20-arithmetics/30-composition/ru/EXERCISE.md b/modules/20-arithmetics/30-composition/ru/EXERCISE.md new file mode 100644 index 0000000..a12d8c8 --- /dev/null +++ b/modules/20-arithmetics/30-composition/ru/EXERCISE.md @@ -0,0 +1,8 @@ + +Реализуйте программу, которая вычисляет и выводит на экран значение выражения: + +``` +8 / 2 + 5 - -3 / 2 +``` + +Не вычисляйте ничего самостоятельно, ваша программа должна производить все вычисления сама. diff --git a/modules/20-arithmetics/30-composition/ru/README.md b/modules/20-arithmetics/30-composition/ru/README.md new file mode 100644 index 0000000..3d6b317 --- /dev/null +++ b/modules/20-arithmetics/30-composition/ru/README.md @@ -0,0 +1,23 @@ +А что, если понадобится вычислить такое выражение: `3 * 5 - 2`? Именно так мы и запишем: + +```javascript +console.log(3 * 5 - 2); // => 13 +``` + +Обратите внимание, что интерпретатор производит арифметические вычисления в правильном порядке: сначала деление и умножение, потом сложение и вычитание. Иногда этот порядок нужно изменить — об этом следующий урок. + +Или другой пример: + +```javascript +console.log(2 * 4 * 5 * 10); +``` + +https://replit.com/@hexlet/js-basics-arithmetics-composition + +Как видно, операции можно соединять друг с другом, получая возможность вычислять все более сложные составные выражения. Чтобы представить себе то, как происходят вычисления внутри интерпретатора, давайте разберем пример: `2 * 4 * 5 * 10`. + +1. Сначала вычисляется `2 * 4` и получается выражение `8 * 5 * 10`. +1. Затем `8 * 5`. В итоге имеем `40 * 10`. +3. В конце концов происходит последнее умножение, и получается результат `400`. + +Таким образом, интерпретатор соединяет сложные составные выражения, последовательно выполняя заложенные в них арифметические действия, по умолчанию соблюдая правильный порядок: сначала умножение и деление, затем - сложение и вычитание. diff --git a/modules/20-arithmetics/30-composition/ru/data.yml b/modules/20-arithmetics/30-composition/ru/data.yml new file mode 100644 index 0000000..3dda1ff --- /dev/null +++ b/modules/20-arithmetics/30-composition/ru/data.yml @@ -0,0 +1,6 @@ +name: Композиция операций +tips: [] +definitions: + - name: Композиция + description: | + метод объединения нескольких простых операций в одну сложную. diff --git a/modules/20-arithmetics/40-priority/ru/EXERCISE.md b/modules/20-arithmetics/40-priority/ru/EXERCISE.md new file mode 100644 index 0000000..0b63f8c --- /dev/null +++ b/modules/20-arithmetics/40-priority/ru/EXERCISE.md @@ -0,0 +1,4 @@ + +Дано выражение `70 * 3 + 4 / 8 + 2`. + +Расставьте скобки так, чтобы оба сложения (`3 + 4`) и (`8 + 2`) высчитывались в первую очередь. Выведите результат на экран. diff --git a/modules/20-arithmetics/40-priority/ru/README.md b/modules/20-arithmetics/40-priority/ru/README.md new file mode 100644 index 0000000..2eaa208 --- /dev/null +++ b/modules/20-arithmetics/40-priority/ru/README.md @@ -0,0 +1,32 @@ +Посмотрите внимательно на выражение `2 + 2 * 2` и посчитайте в уме ответ. + +Правильный ответ: `6`. + +Если у вас получилось `8`, то этот урок для вас. В школьной математике мы изучали понятие «приоритет операции». Приоритет определяет то, в какой последовательности должны выполняться операции. Например, умножение и деление имеют больший приоритет, чем сложение и вычитание, а приоритет возведения в степень выше всех остальных арифметических операций: `2 ** 3 * 2` вычислится в `16`. + +Но нередко вычисления должны происходить в порядке, отличном от стандартного приоритета. В сложных ситуациях приоритет можно (и нужно) задавать круглыми скобками, точно так же, как в школе, например: `(2 + 2) * 2`. + +Скобки можно ставить вокруг любой операции. Они могут вкладываться друг в друга сколько угодно раз. Вот пара примеров: + +```javascript +console.log(3 ** (4 - 2)); // => 9 +console.log(7 * 3 + (4 / 2) - (8 + (2 - 1))); // => 14 +``` + +Иногда выражение сложно воспринимать визуально. Тогда можно расставить скобки, не повлияв на приоритет. Например, задание из прошлого урока можно сделать немного понятнее, если расставить скобки. + +Было: + +```javascript +console.log(8 / 2 + 5 - -3 / 2); // => 10.5 +``` + +Стало: + +```javascript +console.log(((8 / 2) + 5) - (-3 / 2)); // => 10.5 +``` + +https://replit.com/@hexlet/js-basics-arithmetics#index.js + +Запомните: код пишется для людей, потому что код будут читать люди, а машины будут только исполнять его. Для машин код — или корректный, или не корректный, для них нет «более» понятного или «менее» понятного кода. diff --git a/modules/20-arithmetics/40-priority/ru/data.yml b/modules/20-arithmetics/40-priority/ru/data.yml new file mode 100644 index 0000000..0d715b9 --- /dev/null +++ b/modules/20-arithmetics/40-priority/ru/data.yml @@ -0,0 +1,10 @@ +name: Приоритет операций +tips: + - > + [Приоритет + операторов](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Operator_Precedence) +definitions: + - name: Выражение + description: > + последовательность действий над данными, приводящая к каком-то результату, + который можно использовать. diff --git a/modules/20-arithmetics/50-float/ru/EXERCISE.md b/modules/20-arithmetics/50-float/ru/EXERCISE.md new file mode 100644 index 0000000..6b472cb --- /dev/null +++ b/modules/20-arithmetics/50-float/ru/EXERCISE.md @@ -0,0 +1,2 @@ + +Вычислите и выведите на экран произведение двух чисел: *0.39* и *0.22* diff --git a/modules/20-arithmetics/50-float/ru/README.md b/modules/20-arithmetics/50-float/ru/README.md new file mode 100644 index 0000000..042805f --- /dev/null +++ b/modules/20-arithmetics/50-float/ru/README.md @@ -0,0 +1,25 @@ + +JavaScript не делает различий между рациональными (0.5) и натуральными числами (10), для него и то, и другое - числа (в других языках это не так). Благодаря этому их можно использовать совместно в любых операциях: + +```javascript +3 * 0.5; // 1.5 +``` + +Но как бы от нас ни скрывали, рациональные числа, в силу своих особенностей, устроены совсем по-другому. Нам, как прикладным программистам, это было бы не особенно важно, если бы не одна деталь. Посмотрите на этот пример: + +```javascript +// Проверьте этот код в консоли браузера +0.2 * 0.2 // 0.04000000000000001 +``` + +Операция умножения двух рациональных чисел внезапно привела к неточному вычислению результата. Тот же самый результат выдадут и другие языки программирования. Такое поведение обуславливается ограничениями вычислительных мощностей. Объем памяти, в отличие от чисел, конечен (бесконечное количество чисел требует бесконечного количества памяти для своего хранения). И если с натуральными числами эта проблема решается простым ограничением по верхней границе (есть некоторое максимальное число, которое можно ввести), то с рациональными такой финт не пройдет. + +```javascript +// Максимальное возможное целое число +console.log(Number.MAX_SAFE_INTEGER); +9007199254740991 +``` + +Рациональные числа не выстроены в непрерывную цепочку, между _0.1_ и _0.2_ бесконечное множество чисел. Соответственно возникает серьезная проблема, а как хранить рациональные числа? Это интересный вопрос сам по себе. В интернете множество статей, посвященных организации памяти в таких случаях. Более того, существует стандарт, в котором описано, как это делать правильно, и подавляющее число языков на него опирается. + +Для нас, как для разработчиков, важно понимать, что операции с плавающими числами неточны (эту точность можно регулировать), а значит при решении задач, связанных с подобными числами, необходимо прибегать к специальным трюкам, которые позволяют добиться необходимой точности. diff --git a/modules/20-arithmetics/50-float/ru/data.yml b/modules/20-arithmetics/50-float/ru/data.yml new file mode 100644 index 0000000..8e11b15 --- /dev/null +++ b/modules/20-arithmetics/50-float/ru/data.yml @@ -0,0 +1,9 @@ +name: Числа с плавающей точкой +tips: + - > + [Что нужно знать про арифметику с плавающей + запятой](https://habr.com/post/112953/) +definitions: + - name: Рациональное число + description: | + число, которое можно представить в виде обыкновенной дроби. diff --git a/modules/20-arithmetics/60-infinity/ru/EXERCISE.md b/modules/20-arithmetics/60-infinity/ru/EXERCISE.md new file mode 100644 index 0000000..ec116af --- /dev/null +++ b/modules/20-arithmetics/60-infinity/ru/EXERCISE.md @@ -0,0 +1,2 @@ + +Распечатайте на экран сумму бесконечностей, поделенную на 10 diff --git a/modules/20-arithmetics/60-infinity/ru/README.md b/modules/20-arithmetics/60-infinity/ru/README.md new file mode 100644 index 0000000..077f64f --- /dev/null +++ b/modules/20-arithmetics/60-infinity/ru/README.md @@ -0,0 +1,18 @@ + +В программировании широко известна ошибка "деление на ноль". В низкоуровневых языках она приводит к краху программы и необходимости ее перезапуска. Там, где другие падают, JavaScript продолжает работать. + +```javascript +console.log(1 / 0); // ? +``` + +https://replit.com/@hexlet/js-basics-arithmetics-inifinity + +Попробуйте выполнить этот код в браузере. На экран выведется `Infinity` (бесконечность)! Для тех, кто изучал высшую математику (привет, матан!), в этом нет ничего удивительного. Деление на ноль действительно создает бесконечность. Бесконечность в JavaScript — самое настоящее число, с которым возможно проводить различные операции. В повседневных задачах смысла от этого мало, так как большинство операций с бесконечностью завершаются созданием бесконечности, например, при прибавлении любого числа к бесконечности мы все равно получим бесконечность. + +```javascript +Infinity + 4; // Infinity +Infinity - 4; // Infinity +Infinity * Infinity; // Infinity +``` + +Однако есть несколько примеров, где бесконечность нужна. Подробнее этот вопрос рассматривается на Хекслете. diff --git a/modules/20-arithmetics/60-infinity/ru/data.yml b/modules/20-arithmetics/60-infinity/ru/data.yml new file mode 100644 index 0000000..7f34a60 --- /dev/null +++ b/modules/20-arithmetics/60-infinity/ru/data.yml @@ -0,0 +1,11 @@ +name: Бесконечность (Infinity) +tips: + - > + [Infinity](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Infinity) +definitions: + - name: Бесконечность + description: > + Бесконечность в математике и физике не является числом и означает "без + конца" или "без границ".Бесконечность обычно рассматривается как число, + поскольку оно используется для обозначения чисел вещей, но это не реальное + число. diff --git a/modules/20-arithmetics/70-nan/ru/EXERCISE.md b/modules/20-arithmetics/70-nan/ru/EXERCISE.md new file mode 100644 index 0000000..8574dd9 --- /dev/null +++ b/modules/20-arithmetics/70-nan/ru/EXERCISE.md @@ -0,0 +1,2 @@ + +Выполните операцию, которая приводит к NaN, и распечатайте её результат на экран с помощью `console.log()`. diff --git a/modules/20-arithmetics/70-nan/ru/README.md b/modules/20-arithmetics/70-nan/ru/README.md new file mode 100644 index 0000000..64c0cc7 --- /dev/null +++ b/modules/20-arithmetics/70-nan/ru/README.md @@ -0,0 +1,15 @@ +Некоторые операции с бесконечностями приводят к странному результату, например, деление бесконечности на бесконечность. В математике такая операция не имеет никакого числового эквивалента. В JavaScript вернется `NaN`. + +```javascript +Infinity / Infinity; // NaN +``` + +`NaN` - специальное значение "не число", которое обычно говорит о том, что была выполнена бессмысленная операция. Результатом практически любой операции, в которой участвует `NaN`, будет `NaN`. + +```javascript +NaN + 1; // NaN +``` + +https://replit.com/@hexlet/js-basics-arithmetics-NaN + +`NaN` интересное значение, хотя оно обозначает "не число" — с точки зрения типов, оно является числом. Парадокс. `NaN` никогда не является желаемым значением и появляется только в результате ошибок. Если вы его встретили, то нужно отследить момент, в котором выполнилась операция, недопустимая для чисел, и поправить это место. diff --git a/modules/20-arithmetics/70-nan/ru/data.yml b/modules/20-arithmetics/70-nan/ru/data.yml new file mode 100644 index 0000000..57e666f --- /dev/null +++ b/modules/20-arithmetics/70-nan/ru/data.yml @@ -0,0 +1,4 @@ +name: NaN +tips: + - > + [NaN](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/NaN) diff --git a/modules/20-arithmetics/80-linting/ru/EXERCISE.md b/modules/20-arithmetics/80-linting/ru/EXERCISE.md new file mode 100644 index 0000000..4926498 --- /dev/null +++ b/modules/20-arithmetics/80-linting/ru/EXERCISE.md @@ -0,0 +1,2 @@ + +Выведите на экран результат следующего вычисления: «разница между пятью в квадрате и произведением трёх и семи». Расставьте скобки таким образом, чтобы не нарушать правило `no-mixed-operators`. diff --git a/modules/20-arithmetics/80-linting/ru/README.md b/modules/20-arithmetics/80-linting/ru/README.md new file mode 100644 index 0000000..a0cc2ad --- /dev/null +++ b/modules/20-arithmetics/80-linting/ru/README.md @@ -0,0 +1,38 @@ +Теперь, когда мы уже научились писать простые программы, можно немного поговорить о том, как их писать. + +Код программы следует оформлять определенным образом, чтобы он был достаточно понятным и простым в поддержке. Специальные наборы правил — стандарты — описывают различные аспекты написания кода. Конкретно в JavaScript самым распространенным стандартом является стандарт от [AirBnb](https://github.com/airbnb/javascript). + +В любом языке программирования существуют утилиты — так называемые **линтеры**. Они проверяют код на соответствие стандартам. В JavaScript это [eslint](https://eslint.org/). + +Взгляните на пример из предыдущего урока: + +```javascript +console.log(8/2+5 - -3 / 2); // => 10.5 +``` + +Линтер будет «ругаться» на нарушение сразу нескольких правил: + + * [space-infix-ops](https://eslint.org/docs/rules/space-infix-ops) – Отсутствие пробелов между оператором и операндами. + * [no-mixed-operators](https://eslint.org/docs/rules/no-mixed-operators) – По стандарту нельзя писать код, в котором разные операции используются в одном выражении без явного разделения скобками. + +В прошлом уроке мы сами признали, что такое обилие цифр и символов запутывает, и решили добавить скобки исключительно для удобства чтения: + +```javascript +console.log(((8 / 2) + 5) - (-3 / 2)); // => 10.5 +``` + +Этот вариант уже не нарушает правил, и линтер будет «молчать». + +В упражнении прошлого урока у вас скорее всего получилось так: + +```javascript +console.log(70 * (3 + 4) / (8 + 2)); +``` + +Есть ли здесь нарушение стандарта? + +К сожалению, да. На этот раз операции `*` и `/` находятся в одном выражении без разделения скобками. Вы можете решить эту проблему, добавив дополнительные скобки. Но в какой-то момент количество скобок может быть уже настолько большим, что код снова станет неудобным и непонятным. В этот момент разумнее будет разделить выражение на отдельные части. Мы научимся это делать в следующих уроках. + +[no-mixed-operators](https://eslint.org/docs/rules/no-mixed-operators) — лишь одно из большого количества правил. Другие правила описывают отступы, названия создаваемых сущностей, скобки, математические операции, длину строк и множество иных аспектов. Каждое отдельное правило кажется довольно мелким, не очень важным. Но вместе они составляют основу хорошего кода. + +Сейчас сайт не будет проверять ваш код линтером, но в ваших будущих практиках на [Хекслете](https://ru.hexlet.io) и в реальной разработке линтер будет работать и сообщать вам о нарушениях. diff --git a/modules/20-arithmetics/80-linting/ru/data.yml b/modules/20-arithmetics/80-linting/ru/data.yml new file mode 100644 index 0000000..7909b71 --- /dev/null +++ b/modules/20-arithmetics/80-linting/ru/data.yml @@ -0,0 +1,4 @@ +name: Линтер +tips: + - | + [eslint](https://eslint.org/) diff --git a/modules/25-strings/10-quotes/ru/EXERCISE.md b/modules/25-strings/10-quotes/ru/EXERCISE.md new file mode 100644 index 0000000..9ce89ad --- /dev/null +++ b/modules/25-strings/10-quotes/ru/EXERCISE.md @@ -0,0 +1,12 @@ + +Напишите программу, которая выведет на экран: + +``` +"Khal Drogo's favorite word is "athjahakar"" +``` + +Программа должна в точности вывести на экран именно эту фразу. Обратите внимание на кавычки в начале и в конце фразы: + +
+"Khal Drogo's favorite word is "athjahakar"" +diff --git a/modules/25-strings/10-quotes/ru/README.md b/modules/25-strings/10-quotes/ru/README.md new file mode 100644 index 0000000..2ed57ef --- /dev/null +++ b/modules/25-strings/10-quotes/ru/README.md @@ -0,0 +1,87 @@ + +```javascript +'Hello' +'Goodbye' +'G' +' ' +'' +``` + +Какие из этих пяти вариантов — строки? + +С первыми двумя все понятно, это точно строки, мы уже работали с подобными конструкциями и говорили, что строки - это наборы символов. + +Любой одиночный символ в кавычках — это строка. Пустая строка `''` — это тоже строка. То есть строкой мы считаем всё, что находится внутри кавычек, даже если это пробел, один символ или вообще отсутствие символов. + +Ранее в уроках мы записывали строки в одинарных кавычках, но это не единственный способ. Можно использовать и двойные: + +```javascript +// Стандарт кодирования airbnb, рекомендует +// использовать, по возможности, одинарные +console.log("Dracarys!"); +``` + +Представьте, что вы хотите напечатать строчку _Dragon's mother_. Апостроф перед буквой **s** — это такой же символ, как одинарная кавычка. Попробуем: + +```javascript +console.log('Dragon's mother'); +// Uncaught SyntaxError: missing ) after argument list +``` + +Такая программа не будет работать. С точки зрения JavaScript, строка началась с одинарной кавычки, а потом закончилась после буквы **n**. Дальше были символы `s mother` без кавычек — значит, это не строка. А потом была одна открывающая строку кавычка, которая так и не закрылась: `');`. Этот код синтаксически некорректен (это видно даже по тому, как подсвечен код). + +Здесь нам помогут двойные кавычки. Такой вариант программы отработает корректно: + +```javascript +console.log("Dragon's mother"); +``` + +Теперь интерпретатор знает, что строка началась с двойной кавычки — значит, и закончиться должна на двойной кавычке. А одинарная кавычка внутри стала частью строки. + +Верно и обратное. Если внутри строки мы хотим использовать двойные кавычки, то саму строку надо делать в одинарных. Причем количество кавычек внутри самой строки не важно. + +А что, если мы хотим создать такую строку: + +``` +Dragon's mother said "No" +``` + +В ней есть и одинарные и двойные кавычки. Как быть в этой ситуации? Нужно каким-то образом сказать интерпретатору считать каждую кавычку частью строки, а не началом или концом строки. + +Для этого **экранируют** специальные символы. В нашем случае тот символ, который является признаком конца и начала строки, это либо одинарная кавычка, либо двойная, в зависимости от ситуации. Для экранирования используется обратный слеш `\`. + +```javascript +// Экранируется только ", так как в этой ситуации +// двойные кавычки имеют специальное значение +console.log("Dragon's mother said \"No\""); +// => Dragon's mother said "No" +``` + +Посмотрите внимательно: нам нужно было добавить `\` для двойных кавычек, но не для одинарной (апостроф), потому что сама строка создана с двойными кавычками. Если бы строка создавалась с одинарными кавычками, то символ экранирования нужен был бы перед апострофом, но не перед двойными кавычками. + +```javascript +// \ не выводится, если после него идет обычный, +// а не специальный символ +console.log("Death is \so terribly final"); +// => Death is so terribly final +``` + +А что, если нужно вывести сам обратный слеш? Точно так же, как и любой другой специальный символ, его надо экранировать самим собой. + +```javascript +console.log("\\"); +// => \ +``` + +Вопрос на самопроверку, что выведет этот код? + +```javascript +console.log("\\ \\ \\\\ \\\ \'\""); +``` + +
+- Привет!¶ +- О, привет!¶ +- Как дела? ++ +Устройство, которое выводит соответствующий текст, учитывает этот символ. Например, принтер при встрече с LF протаскивает бумагу вверх на одну строку, а текстовый редактор переносит весь последующий текст ниже, также на одну строку. + +`\n` — это пример **экранирующей последовательности** (escape sequence). Их ещё называют управляющими конструкциями. Хотя таких символов не один десяток, в программировании часто встречаются всего несколько. Кроме перевода строки, к таким символам относятся табуляция (разрыв, получаемый при нажатии на кнопку Tab) и возврат каретки (только в Windows). Нам, программистам, часто нужно использовать перевод строки `\n` для правильного форматирования текста. + +```javascript +console.log('Gregor Clegane\nDunsen\nPolliver\nChiswyck'); +``` + +На экран выведется: + +``` +Gregor Clegane +Dunsen +Polliver +Chiswyck +``` + +Обратите внимание на следующие моменты: + +1. Не имеет значения, что стоит перед или после `\n`: символ или пустая строка. Перевод будет обнаружен и выполнен в любом случае. + +2. Помните, что строка может содержать один символ или вообще ноль символов. А еще строка может содержать только `\n`. Проанализируйте следующий пример: + + ```javascript + console.log('\n'); + console.log('Dunsen'); + ``` + + Здесь мы сначала выводим строку «перевод строки», а потом делаем вывод обыкновенной строки. Программа выведет на экран: + +
++ + Почему перед строкой *Dunsen* появилось две пустые строки, а не одна? Дело в том, что `console.log()` при выводе значения автоматически добавляет в конец символ перевода строки. Таким образом, один перевод строки мы указали явно, передав этот символ экранирующей последовательности аргументом в функцию, а второй перевод строки добавлен самой функцией автоматически. + + Ещё пример кода: + + ```javascript + console.log('Polliver'); + console.log('Gregor Clegane'); + console.log(); + console.log('Chiswyck'); + console.log('\n'); + console.log('Dunsen'); + ``` + + Вывод будет таким: + +
+ Dunsen +
+ Polliver + Gregor Clegane+ + Сейчас у вас достаточно знаний, чтобы самостоятельно разобраться и понять, почему вывод сформировался именно таким образом. + +3. Если нам понадобится вывести `\n` именно как текст (два отдельных печатных символа), то можно воспользоваться уже известным нам способом экранирования, добавив еще один `\` в начале. То есть последовательность `\\n` отобразится как символы `\` и `n`, идущие друг за другом. + +```javascript +console.log('Joffrey loves using \\n'); +``` + +на экран выйдет: + +
+ Chiswyck
+ + Dunsen +
+Joffrey loves using \n ++ +Небольшое, но важное замечание про Windows. В Windows для перевода строк по умолчанию используется `\r\n`. Такая комбинация хорошо работает только в Windows, но создаёт проблемы при переносе в другие системы (например, когда в команде разработчиков есть пользователи как Windows, так и Linux). Дело в том, что последовательность `\r\n` имеет разную трактовку в зависимости от выбранной кодировки (рассматривается позже). По этой причине, в среде разработчиков принято всегда использовать `\n` без `\r`, так как LF всегда трактуется одинаково и отлично работает в любой системе. Не забудьте настроить ваш редактор на использование `\n`. diff --git a/modules/25-strings/15-escape-characters/ru/data.yml b/modules/25-strings/15-escape-characters/ru/data.yml new file mode 100644 index 0000000..ec3c5fd --- /dev/null +++ b/modules/25-strings/15-escape-characters/ru/data.yml @@ -0,0 +1,13 @@ +name: Экранирующие последовательности +definitions: + - name: Экранирующая последовательность + description: > + специальная комбинация символов в тексте. Например, `\n` — это перевод + строки. +tips: + - > + Обязательно поэкспериментируйте с выводом разных строк на сайте + [https://replit.com/languages/nodejs](https://replit.com/languages/nodejs) + - > + [История перевода + строки](https://ru.wikipedia.org/wiki/Перевод_строки#История) diff --git a/modules/25-strings/20-string-concatenation/ru/EXERCISE.md b/modules/25-strings/20-string-concatenation/ru/EXERCISE.md new file mode 100644 index 0000000..0b97df9 --- /dev/null +++ b/modules/25-strings/20-string-concatenation/ru/EXERCISE.md @@ -0,0 +1,8 @@ + +Выведите на экран + +``` +Winter came for the House of Frey. +``` + +используя конкатенацию слов. diff --git a/modules/25-strings/20-string-concatenation/ru/README.md b/modules/25-strings/20-string-concatenation/ru/README.md new file mode 100644 index 0000000..cb0721b --- /dev/null +++ b/modules/25-strings/20-string-concatenation/ru/README.md @@ -0,0 +1,48 @@ + +В веб-разработке программы постоянно оперируют строками. Всё, что мы видим на сайтах, так или иначе представлено в виде текста. Этот текст чаще всего динамический, то есть полученный из разных частей, которые соединяются вместе. Операция соединения строк в программировании называется **конкатенацией**. + +```javascript +// Оператор такой же, как и при сложении чисел +// но здесь он имеет другой смысл (семантику) +console.log('Dragon' + 'stone'); +// => Dragonstone +``` + +Склеивание строк всегда происходит в том же порядке, в котором записаны операнды. Левый операнд становится левой частью строки, а правый — правой. + +Вот еще несколько примеров: + +```javascript +console.log('Kings' + 'wood'); // => Kingswood + +// Обратный порядок слов +console.log('road' + 'Kings'); // => roadKings + +// Конкатенировать можно абсолютно любые строки +console.log("King's" + 'Landing'); // => King'sLanding +``` + +Как видите, строки можно склеивать, даже если они записаны с разными кавычками. + +В последнем примере название города получилось с ошибкой: *King's Landing* нужно писать через пробел. Но в наших начальных строках не было пробелов, а пробелы в самом коде слева и справа от символа `+` не имеют значения, потому что они не являются частью строк. + +Выхода из этой ситуации два: + +```javascript +// Оба способа равнозначны + +// Ставим пробел в левой части +console.log("King's " + 'Landing'); // => King's Landing +// Ставим пробел в правой части +console.log("King's" + ' Landing'); // => King's Landing +``` + +Пробел — такой же символ, как и другие. Чем больше пробелов, тем шире отступы: + +```javascript +console.log("King's " + ' Landing'); // => King's Landing + +console.log("King's " + ' Landing'); // => King's Landing +``` + +https://replit.com/@hexlet/js-basics-strings diff --git a/modules/25-strings/20-string-concatenation/ru/data.yml b/modules/25-strings/20-string-concatenation/ru/data.yml new file mode 100644 index 0000000..9a53953 --- /dev/null +++ b/modules/25-strings/20-string-concatenation/ru/data.yml @@ -0,0 +1,10 @@ +name: Конкатенация +tips: + - > + Если в редакторе есть запись `// BEGIN` и `// END`, то код нужно писать + между этими строчками. +definitions: + - name: Конкатенация + description: > + операция соединения двух строк. Например, `console.log("King's " + ' + Landing');` diff --git a/modules/25-strings/30-encoding/ru/EXERCISE.md b/modules/25-strings/30-encoding/ru/EXERCISE.md new file mode 100644 index 0000000..b6e7f9c --- /dev/null +++ b/modules/25-strings/30-encoding/ru/EXERCISE.md @@ -0,0 +1,16 @@ + +В JavaScript можно «запросить» и вывести на экран любой символ из кодировки ASCII. Например: + +```javascript +console.log(String.fromCharCode(63)); +``` + +На экран выведется символ с номером 63 — вопросительный знак `?`. Таким способом можно выводить любой символ. + +https://replit.com/@hexlet/js-basics-strings-encoding + +Найдите в интернете таблицу кодов ASCII. Можно использовать запросы типа "ascii codes table" или «коды ascii». Обычно в таких таблицах коды указаны сразу в нескольких системах счисления: десятичной, двоичной, восьмеричной и шестнадцатеричной. Нас интересует десятичный код (*dec* или *decimal*). + +Используя пример выше и найденную таблицу, выведите на экран символы `~`, `^` и `%` (каждый на своей собственной строке). + +(Конечно, можно «обмануть» тесты и просто сделать что-то типа `console.log('~')`, но так будет совсем неинтересно :) diff --git a/modules/25-strings/30-encoding/ru/README.md b/modules/25-strings/30-encoding/ru/README.md new file mode 100644 index 0000000..fa65857 --- /dev/null +++ b/modules/25-strings/30-encoding/ru/README.md @@ -0,0 +1,37 @@ + +На самом глубоком уровне компьютер оперирует исключительно цифрами `0` и `1`. Это так называемый [двоичный код](https://ru.wikipedia.org/wiki/Двоичный_код), а единички и нули называются битами, от "binary digit" — «двоичная цифра». + +Обычные, привычные нам числа в десятичной системе счисления, закодированы с помощью двоичных чисел: + +- 0 ← 0 +- 1 ← 1 +- 2 ← 10 +- 3 ← 11 +- 4 ← 100 +- 5 ← 101 + +Но как быть с текстом? Компьютер на самом деле не знает ничего о буквах, знаках пунктуации и прочих текстовых символах. Все эти символы также закодированы числами. + +Можно взять английский алфавит и дать каждой букве число, начиная с единицы по порядку: + +- a ← 1 +- b ← 2 +- c ← 3 +- d ← 4 +- ... +- z ← 26 + +Далее можно научить компьютер понимать эту таблицу и переводить текст в числа и наоборот — числа в текст: + +- `hello` → `8` `5` `12` `12` `15` +- `7` `15` `15` `4` → `good` + +Подобные таблицы, в которых сопоставляются буквы и числа, называются кодировками. Кроме букв алфавита, в таблицы кодировок входят знаки препинания и другие полезные символы. Вы наверняка сталкивались с кодировками, например, [ASCII](https://ru.wikipedia.org/wiki/ASCII) или [UTF-8](https://ru.wikipedia.org/wiki/UTF-8). + +Разные кодировки содержат различное количество символов. Изначально небольших таблиц вроде ASCII было достаточно для большинства задач. Но в ней есть только латинские буквы, несколько простых символов вроде `%` и `?` и специальные управляющие символы типа перевода строки. + +С распространением компьютеров, разным странам понадобились свои, более широкие таблицы. В том числе для кириллических букв, иероглифов, арабской вязи, дополнительных математических и типографских символов, а впоследствии — даже для эмодзи-смайликов. + +Сегодня в большинстве случаев используется один из вариантов [юникода](https://ru.wikipedia.org/wiki/Юникод) — *utf-8*. Он включает в себя знаки почти всех письменных языков мира. Благодаря этому, письмо, сформированное человеком в Китае на китайском, без проблем можно открыть и увидеть в первозданном виде на компьютере в Финляндии (поймет он его или нет, это уже другой вопрос). + +С кодированием текста и кодировками программисты встречаются в своей жизни регулярно. Поддержка юникода у разных языков программирования выполнена на разном уровне. Кроме того, кодировки нужно явно указывать при работе и с базами данных, и с файлами. diff --git a/modules/25-strings/30-encoding/ru/data.yml b/modules/25-strings/30-encoding/ru/data.yml new file mode 100644 index 0000000..a0ce3ed --- /dev/null +++ b/modules/25-strings/30-encoding/ru/data.yml @@ -0,0 +1,9 @@ +name: Кодировка +tips: + - | + [Что такое кодировки?](https://guides.hexlet.io/ru/encoding/) +definitions: + - name: Кодировка + description: >- + набор символов, закодированных с помощью чисел для представления текста в + электронном виде. diff --git a/modules/30-variables/10-definition/ru/EXERCISE.md b/modules/30-variables/10-definition/ru/EXERCISE.md new file mode 100644 index 0000000..a112dab --- /dev/null +++ b/modules/30-variables/10-definition/ru/EXERCISE.md @@ -0,0 +1,2 @@ + +Создайте переменную с именем `motto` и содержимым `What Is Dead May Never Die!`. Распечатайте содержимое переменной. diff --git a/modules/30-variables/10-definition/ru/README.md b/modules/30-variables/10-definition/ru/README.md new file mode 100644 index 0000000..32fa509 --- /dev/null +++ b/modules/30-variables/10-definition/ru/README.md @@ -0,0 +1,49 @@ + +Представьте себе задачу: нам нужно напечатать на экран фразу *Father!* два раза или даже пять раз. Эту задачу можно решить в лоб: + +```javascript +console.log('Father!'); +console.log('Father!'); +``` + +В простейшем случае так и стоит поступить, но если фраза *Father!* начнет использоваться чаще, да еще и в разных частях программы, то придется ее везде повторять. Проблемы с таким подходом начнутся тогда, когда понадобится изменить нашу фразу, а такое происходит довольно часто. Нам придется найти все места, где использовалась фраза *Father!*, и выполнить необходимую замену. А можно поступить по-другому. Вместо копирования нашего выражения достаточно создать переменную с этой фразой. + +```javascript +// greeting - переводится как приветствие +let greeting = 'Father!'; +console.log(greeting); // => Father! +console.log(greeting); // => Father! +``` + +Переменная указывает на данные, которые были в неё записаны. Благодаря этому, данные можно использовать многократно без необходимости их постоянно дублировать. Сама переменная создается и наполняется данными (инициализируется) с помощью инструкции `let greeting = 'Father!'`. + +Для имени переменной используется любой набор допустимых символов, к которым относятся буквы английского алфавита, цифры, а также знаки *_* и *$*. При этом цифру нельзя ставить в начале. Имена переменных регистрозависимы, то есть имя `hello` и имя `heLLo` - это два разных имени, а значит и две переменные. Регистр в JavaScript имеет важное значение, никогда не забывайте про него. + +Переменную не обязательно инициализировать данными во время объявления. Иногда бывает нужно ее создать, а наполняться она будет потом: + +```javascript +let greeting; + +// Использование +console.log(greeting); // undefined + +// Изменение переменной в следующем уроке +``` + +Объявленная, но не инициализированная переменная, содержит внутри себя значение `undefined`. Это специальное значение, используемое тогда, когда ничего не определено. + +Количество создаваемых переменных ничем не ограничено, большие программы содержат десятки и сотни тысяч имен переменных: + +```javascript +let greeting1 = 'Father!'; +console.log(greeting1); +console.log(greeting1); + +let greeting2 = 'Mother!'; +console.log(greeting2); +console.log(greeting2); +``` + +https://replit.com/@hexlet/js-basics-variables-definition + +Для удобства анализа программы, переменные принято создавать как можно ближе к тому месту, где они используются. diff --git a/modules/30-variables/10-definition/ru/data.yml b/modules/30-variables/10-definition/ru/data.yml new file mode 100644 index 0000000..d4f5eac --- /dev/null +++ b/modules/30-variables/10-definition/ru/data.yml @@ -0,0 +1,9 @@ +name: Что такое переменная +tips: + - > + [let](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/let) +definitions: + - name: Переменная + description: >- + способ сохранить информацию и дать ей имя для последующего использования в + коде. diff --git a/modules/30-variables/11-change/ru/EXERCISE.md b/modules/30-variables/11-change/ru/EXERCISE.md new file mode 100644 index 0000000..4371511 --- /dev/null +++ b/modules/30-variables/11-change/ru/EXERCISE.md @@ -0,0 +1,2 @@ + +В упражнении определена переменная, внутри которой находится строка. Переопределите значение этой переменной и присвойте ей ту же строку, но в перевернутом виде, т.е. расположите символы первоначальной строки в обратном порядке. diff --git a/modules/30-variables/11-change/ru/README.md b/modules/30-variables/11-change/ru/README.md new file mode 100644 index 0000000..cf430d2 --- /dev/null +++ b/modules/30-variables/11-change/ru/README.md @@ -0,0 +1,16 @@ + +Само слово "переменная" говорит о том, что ее можно менять. И действительно, с течением времени внутри программы значения переменных могут изменяться. + +```javascript +let greeting = 'Father!'; +console.log(greeting); +console.log(greeting); + +greeting = 'Mother!'; +console.log(greeting); +console.log(greeting); +``` + +https://replit.com/@hexlet/js-basics-variables-change + +Имя осталось тем же, но внутри другие данные. Обратите внимание на ключевое различие между объявлением переменной и ее изменением. Ключевое слово `let` ставится только при создании переменной, но при изменении оно уже не используется. diff --git a/modules/30-variables/11-change/ru/data.yml b/modules/30-variables/11-change/ru/data.yml new file mode 100644 index 0000000..3284d02 --- /dev/null +++ b/modules/30-variables/11-change/ru/data.yml @@ -0,0 +1,6 @@ +name: Изменение переменной +definitions: + - name: Переменная + description: >- + способ сохранить информацию и дать ей имя для последующего использования в + коде. diff --git a/modules/30-variables/13-variables-naming/ru/EXERCISE.md b/modules/30-variables/13-variables-naming/ru/EXERCISE.md new file mode 100644 index 0000000..9aaae9c --- /dev/null +++ b/modules/30-variables/13-variables-naming/ru/EXERCISE.md @@ -0,0 +1,2 @@ + +Создайте переменную, описывающую дословно "количество моих братьев", и присвойте ей значение *2*. Распечатайте содержимое переменной. После успешной проверки сравните своё имя с именем, которое используется в учительском решении. diff --git a/modules/30-variables/13-variables-naming/ru/README.md b/modules/30-variables/13-variables-naming/ru/README.md new file mode 100644 index 0000000..c230f17 --- /dev/null +++ b/modules/30-variables/13-variables-naming/ru/README.md @@ -0,0 +1,36 @@ + +Представим себе, что программа из прошлого урока выглядит так: + +```javascript +let x = 'Father!'; +console.log(x); +console.log(x); +``` + +Она по прежнему работает, но в ней изменилось имя переменной на `x`. Компьютеру без разницы, как мы называем переменные, это бездушная машина, но вот программистам — нет. Мы гораздо чаще читаем код, чем пишем. Причём не свой, а написанный другими людьми. От качества и понятности имён переменных зависит половина успеха в анализе кода. + +Лучше посидеть и придумать название, которое описывает суть, смысл переменной, чем назвать её как попало, а в будущем переделывать. Постарайтесь давать им такие имена, чтобы они были максимально понятны без контекста, без изучения окружающего кода. + +Существует общепринятое правило: не используйте транслит для имён, только английский язык. Если вы испытываете сложности с английским, то пользуйтесь переводчиком. Со временем, копаясь в чужом коде, вы сформируете правильные понятия для именования. + +Среди разработчиков есть шутка: «самое сложное в программировании — названия переменных и инвалидация кеша». Придумывать названия и правда сложно. Как бы вы назвали переменную, в которой хранится *количество неоплаченных заказов от клиентов, имеющих задолженность в предыдущем квартале?* + +
+Targaryen +and +Dragon +diff --git a/modules/30-variables/14-errors/ru/README.md b/modules/30-variables/14-errors/ru/README.md new file mode 100644 index 0000000..51b64e0 --- /dev/null +++ b/modules/30-variables/14-errors/ru/README.md @@ -0,0 +1,21 @@ + +Порядок следования инструкций в коде с переменными играет огромное значение. Переменная должна быть определена до того, как будет использована. Ниже пример ошибки, которую очень часто допускают новички: + +```javascript +// Uncaught ReferenceError: greeting is not defined +console.log(greeting); +let greeting = 'Father!'; +``` + +Запуск программы с примера выше завершается ошибкой *ReferenceError: greeting is not defined*. *ReferenceError* - это ошибка обращения, она означает, что в коде используется имя (говорят идентификатор), которое не определено. Причём в самой ошибке об этом говорят прямо: *greeting is not defined*, что переводится как *greeting не определен*. Кроме неправильного порядка определения, в JavaScript встречаются банальные опечатки — как при использовании переменной, так и при её объявлении. + +Количество подобных ошибок уменьшается за счет использования правильно настроенного редактора. Такой редактор подсвечивает имена, которые используются без объявления и предупреждает о возможных проблемах. + +Еще одна распространенная ошибка — попытаться объявить уже объявленную переменную: + +```javascript +let greeting = 'Father!'; +let greeting = 'Father!'; +``` + +Так делать нельзя. Придётся создать новую переменную. diff --git a/modules/30-variables/14-errors/ru/data.yml b/modules/30-variables/14-errors/ru/data.yml new file mode 100644 index 0000000..62f3e5c --- /dev/null +++ b/modules/30-variables/14-errors/ru/data.yml @@ -0,0 +1,9 @@ +name: Ошибки при работе с переменными +tips: + - > + [ReferenceError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ReferenceError) +definitions: + - name: Переменная + description: >- + способ сохранить информацию и дать ей имя для последующего использования в + коде. diff --git a/modules/30-variables/15-variables-expressions/ru/EXERCISE.md b/modules/30-variables/15-variables-expressions/ru/EXERCISE.md new file mode 100644 index 0000000..ace4412 --- /dev/null +++ b/modules/30-variables/15-variables-expressions/ru/EXERCISE.md @@ -0,0 +1,13 @@ + +Напишите программу, которая берет исходное количество евро, записанное в переменную `eurosCount`, переводит евро в доллары и выводит на экран. Затем полученное значение переводит в юани и выводит на новой строчке. + +Пример вывода для 100 евро: + +
+125 +7500 ++ +Считаем, что: +- 1 евро = 1.25 долларов +- 1 доллар = 6.91 юаней diff --git a/modules/30-variables/15-variables-expressions/ru/README.md b/modules/30-variables/15-variables-expressions/ru/README.md new file mode 100644 index 0000000..4828755 --- /dev/null +++ b/modules/30-variables/15-variables-expressions/ru/README.md @@ -0,0 +1,70 @@ + +Переменные полезны не только для хранения и переиспользования информации, но и для упрощения сложных вычислений. Давайте рассмотрим пример: нужно перевести евро в юани через доллары. Подобные конвертации через промежуточную валюту часто делают банки при покупках за рубежом. + +Для начала переведем 50 евро в доллары. Допустим, что один евро — 1.25 долларов: + +```javascript +let dollarsCount = 50 * 1.25; +console.log(dollarsCount); // => 62.5 +``` + +В предыдущем уроке мы записывали в переменную конкретное значение. А здесь `let dollarsCount = 50 * 1.25;` справа от знака равно находится **выражение**. Интерпретатор вычислит результат — `62.5` — и запишет его в переменную. С точки зрения интерпретатора не важно, что перед ним: `62.5` или `50 * 1.25`, для него оба варианта — выражения, которые надо вычислить. И они вычисляются в одно и тоже значение — `62.5`. + +Любая строка — выражение. Конкатенация строк — тоже выражение. Когда интерпретатор видит выражение, он обрабатывает его и генерирует результат — **значение выражения**. Вот несколько примеров выражений, а в комментариях справа от каждого выражения — итоговое значение: + +```javascript +62.5 // 62.5 +50 * 1.25 // 62.5 +120 / 10 * 2 // 24 + +'hello' // hello +'Good' + 'will' // Goodwill +``` + +Правила построения кода (грамматика языка) таковы, что в тех местах, где ожидается выражение, можно поставить любое вычисление (не только математическое, но и, например, строковое — как конкатенация), и программа останется работоспособной. По этой причине невозможно описать и показать все случаи использования всех операций. + +Программы состоят из множества комбинаций выражений, и понимание этой концепции — один из ключевых шагов на вашем пути. + +Основываясь на сказанном выше, подумайте, сработает ли такой код? + +```javascript +let who = "dragon's" + 'mother'; +console.log(who); +``` + +Запустите его на [repl.it](https://repl.it/languages/javascript) и поэкспериментируйте. + +
+The price is 431.875 yuans ++ +Любая переменная может быть частью любого выражения. В момент вычисления, вместо имени переменной подставляется её значение. + +Интерпретатор вычисляет значение `dollarsCount` до того, как эта переменная начнет использоваться в других выражениях. Когда подходит момент использования переменной, Javascript «знает» значение, потому что уже вычислил его. diff --git a/modules/30-variables/15-variables-expressions/ru/data.yml b/modules/30-variables/15-variables-expressions/ru/data.yml new file mode 100644 index 0000000..3d1fc4b --- /dev/null +++ b/modules/30-variables/15-variables-expressions/ru/data.yml @@ -0,0 +1,9 @@ +name: Выражения в определениях +tips: + - | + [Выражение](https://ru.wikipedia.org/wiki/Выражение_(информатика)) +definitions: + - name: Переменная + description: >- + способ сохранить информацию и дать ей имя для последующего использования в + коде. diff --git a/modules/30-variables/18-variable-concatenation/ru/EXERCISE.md b/modules/30-variables/18-variable-concatenation/ru/EXERCISE.md new file mode 100644 index 0000000..9cb066e --- /dev/null +++ b/modules/30-variables/18-variable-concatenation/ru/EXERCISE.md @@ -0,0 +1,18 @@ + +Сайты постоянно посылают письма своим пользователям. Типичная задача — сделать автоматическую отправку персонального письма, где в заголовке будет имя пользователя. Если где-то в базе сайта хранится имя человека в виде строки, то задача генерации заголовка сводится к конкатенации: например, нужно склеить строку `Здравствуйте` со строкой, где записано имя. + +Напишите программу, которая будет генерировать заголовок и тело письма, используя уже готовые переменные, и выводить получившиеся строки на экран. + +Для заголовка используйте переменные `firstName` и `greeting`, запятую и восклицательный знак. Выведите это на экран в правильном порядке. + +Для тела письма используйте переменные `info` и `intro`, при этом второе предложение должно быть на новой строке. + +Результат на экране будет выглядеть так: + +
+Hello, Joffrey! +Here is important information about your account security. +We couldn't verify your mother's maiden name. ++ +Выполните задание, используя только два `console.log()`. diff --git a/modules/30-variables/18-variable-concatenation/ru/README.md b/modules/30-variables/18-variable-concatenation/ru/README.md new file mode 100644 index 0000000..b850866 --- /dev/null +++ b/modules/30-variables/18-variable-concatenation/ru/README.md @@ -0,0 +1,28 @@ + +Для закрепления предыдущей темы, попробуем использовать переменные с конкатенацией. Синтаксически ничего не меняется: мы умеем конкатенировать (склеивать) две строки: + +```javascript +let what = 'Kings' + 'road'; +console.log(what); // => Kingsroad +``` + +… а значит сумеем конкатенировать строку и одну переменную, в которой записана строка: + +```javascript +let first = 'Kings'; +let what = first + 'road'; + +console.log(what); // => Kingsroad +``` + +… и даже конкатенировать две переменные, в которых записаны строки: + +```javascript +let first = 'Kings'; +let last = 'road'; + +let what = first + last; +console.log(what); // => Kingsroad +``` + +https://replit.com/@hexlet/variables-expression diff --git a/modules/30-variables/18-variable-concatenation/ru/data.yml b/modules/30-variables/18-variable-concatenation/ru/data.yml new file mode 100644 index 0000000..a8708d1 --- /dev/null +++ b/modules/30-variables/18-variable-concatenation/ru/data.yml @@ -0,0 +1,13 @@ +name: Переменные и конкатенация +tips: + - > + Подумайте, с какой строкой и в каком порядке нужно склеивать переменные, + чтобы получить такой двухстрочный вывод тела письма. + - > + Помните, что можно создать строку, которая содержит только управляющую + последовательность `\n`. +definitions: + - name: Конкатенация + description: > + операция соединения двух строк. Например, `console.log("King's " + ' + Landing');` diff --git a/modules/30-variables/19-naming-style/ru/EXERCISE.md b/modules/30-variables/19-naming-style/ru/EXERCISE.md new file mode 100644 index 0000000..1ba3540 --- /dev/null +++ b/modules/30-variables/19-naming-style/ru/EXERCISE.md @@ -0,0 +1,4 @@ + +Создайте две переменные с именами «первое число» и «второе число» на английском языке, используя lowerCamelCase. Запишите в первую переменную число `11`, во вторую — `-100`. Выведите на экран произведение чисел, записанных в получившихся переменных. + +Код будет работать с любыми названиями, а наша система всегда проверяет только результат на экране, поэтому выполнение этого задания — под вашу ответственность. diff --git a/modules/30-variables/19-naming-style/ru/README.md b/modules/30-variables/19-naming-style/ru/README.md new file mode 100644 index 0000000..1ef53b2 --- /dev/null +++ b/modules/30-variables/19-naming-style/ru/README.md @@ -0,0 +1,11 @@ + +`greeting` — пример простого имени, но не все имена так просты. Довольно часто они составные, то есть включают в себя несколько слов. Например, «имя пользователя». В разных языках применяются разные стили кодирования, и имя переменной будет отличаться. + +В именовании переменных можно выделить четыре основных подхода, которые иногда комбинируют друг с другом. Все эти подходы проявляют себя, когда имя переменной состоит из нескольких слов: + +* kebab-case — составные части переменной разделяются дефисом. Например: `my-super-var`. +* snake_case — для разделения используется подчеркивание. Например: `my_super_var`. +* CamelCase — каждое слово в переменной пишется с заглавной буквы. Например: `MySuperVar`. +* lowerCamelCase — каждое слово в переменной пишется с заглавной буквы, кроме первого. Например: `mySuperVar`. + +В Javascript используется CamelCase и его вариация lowerCamelCase, при котором первая буква первого слова — строчная. Именно lowerCamelCase применяется для переменных. Это значит, что имена соединяются друг с другом, при этом все имена кроме первого становятся с заглавной буквы: `userName`. С тремя словами это выглядит так: `mySuperVariable`. diff --git a/modules/30-variables/19-naming-style/ru/data.yml b/modules/30-variables/19-naming-style/ru/data.yml new file mode 100644 index 0000000..89f0e6c --- /dev/null +++ b/modules/30-variables/19-naming-style/ru/data.yml @@ -0,0 +1,7 @@ +name: Стили именования +tips: + - | + [CamelCase](https://ru.wikipedia.org/wiki/CamelCase) +definitions: + - name: Стандарт кодирования + description: Набор синтаксических и стилистических правил написания кода. diff --git a/modules/30-variables/20-magic-numbers/ru/EXERCISE.md b/modules/30-variables/20-magic-numbers/ru/EXERCISE.md new file mode 100644 index 0000000..e7f6237 --- /dev/null +++ b/modules/30-variables/20-magic-numbers/ru/EXERCISE.md @@ -0,0 +1,23 @@ + +Вы столкнулись с таким кодом, который выводит на экран общее количество комнат во владении нынешнего короля: + +```javascript +let king = 'King Balon the 6th'; +console.log(king + ' has ' + (6 * 17) + ' rooms.'); +``` + +Как видите, это магические числа: непонятно, что такое 6 и что такое 17. Можно догадаться, если знать историю королевской семьи: каждый новый король получает в наследство все замки от предков и строит новый замок — точную копию родительского. + +Эта странная династия просто плодит одинаковые замки… + +Избавьтесь от магических чисел, создав новые переменные, и выведите текст на экран. + +Получится так: + +
+King Balon the 6th has 102 rooms. ++ +Названия переменных должны передавать смысл чисел, но должны при этом оставаться достаточно короткими и ёмкими для комфортного чтения. + +Помните: код будет работать с любыми названиями, а наша система всегда проверяет только результат на экране, поэтому выполнение этого задания — под вашу ответственность. diff --git a/modules/30-variables/20-magic-numbers/ru/README.md b/modules/30-variables/20-magic-numbers/ru/README.md new file mode 100644 index 0000000..60521fa --- /dev/null +++ b/modules/30-variables/20-magic-numbers/ru/README.md @@ -0,0 +1,31 @@ + +Вспомним один из прошлых уроков: + +```javascript +let dollarsCount = 50 * 1.25; // 62.5 +let rublesCount = dollarsCount * 60; // 3750 + +console.log(rublesCount); +``` + +С точки зрения профессиональной разработки, такой код «пахнет». Так описывают код, который сложен для понимания. И причина здесь вот в чем: уже сейчас, глядя на число `60` и `1.25`, вы скорее всего задаетесь вопросом: «что это за числа?». А представьте, что будет через месяц! А как его поймет новый программист, не видевший код ранее? В нашем примере контекст восстанавливается благодаря грамотному именованию, но в реальной жизни код значительно сложнее, и догадаться до смысла чисел зачастую невозможно. + +Этот «запах» вызывают Magic Numbers (магические числа). Числа, происхождение которых невозможно понять без глубокого знания происходящего внутри данного участка кода. + +Выход из ситуации прост: достаточно создать переменные с правильными именами, как все встанет на свои места. + +```javascript +let dollarsPerEuro = 1.25; +let rublesPerDollar = 60; + +let dollarsCount = 50 * dollarsPerEuro; // 62.5 +let rublesCount = dollarsCount * rublesPerDollar; // 3750 + +console.log(rublesCount); +``` + +Обратите внимание на следующие детали: + +* Именование lowerCamelCase. +* Две новые переменные отделены от последующих вычислений пустой строчкой. Эти переменные имеют смысл и без вычислений, поэтому такое отделение уместно, оно повышает читаемость. +* Получился хорошо именованный и структурированный код, но он длиннее прошлой версии. Так часто бывает, и это нормально. Код должен быть читабельным. diff --git a/modules/30-variables/20-magic-numbers/ru/data.yml b/modules/30-variables/20-magic-numbers/ru/data.yml new file mode 100644 index 0000000..37265ec --- /dev/null +++ b/modules/30-variables/20-magic-numbers/ru/data.yml @@ -0,0 +1,5 @@ +name: Магические числа +tips: + - > + [Магические + числа](https://ru.wikipedia.org/wiki/Магическое_число_(программирование)) diff --git a/modules/30-variables/23-constants/ru/EXERCISE.md b/modules/30-variables/23-constants/ru/EXERCISE.md new file mode 100644 index 0000000..3371830 --- /dev/null +++ b/modules/30-variables/23-constants/ru/EXERCISE.md @@ -0,0 +1,2 @@ + +Создайте константу `army`, присвойте ей значение `the white walkers` и распечатайте её значение на экран. diff --git a/modules/30-variables/23-constants/ru/README.md b/modules/30-variables/23-constants/ru/README.md new file mode 100644 index 0000000..442d833 --- /dev/null +++ b/modules/30-variables/23-constants/ru/README.md @@ -0,0 +1,42 @@ + +Во всем модуле подавляющее большинство примеров кода использовало переменные в качестве имен (псевдонимы) конкретных значений, а не как переменные, которые меняют свое значение со временем. + +```javascript +let dollarsInEuro = 1.25; +let rublesInDollar = 60; + +let dollarsCount = 50 * dollarsInEuro; // 62.5 +let rublesCount = dollarsCount * rublesInDollar; // 3750 + +console.log(rublesCount); +``` + +В программировании принято называть такие имена константами, и многие языки поддерживают константы как конструкцию. JavaScript, как раз, относится к таким языкам, и его стандарты кодирования [говорят прямо](https://eslint.org/docs/rules/prefer-const) — если значение не меняется, то мы имеем дело с константой. Перепишем пример выше на использование констант: + +```javascript +const dollarsInEuro = 1.25; +const rublesInDollar = 60; + +const euros = 1000; +const dollars = euros * dollarsInEuro; // 1250 +const rubles = dollars * rublesInDollar; // 75000 + +console.log(rubles); +``` + +https://replit.com/@hexlet/js-basics-variables + +Единственное изменение заключается в том, что ключевое слово `let` заменилось на `const`, но это только синтаксис. Теперь, если попытаться изменить любую константу, то мы получим сообщение об ошибке. В остальном они используются точно так же, как и переменные. + +```javascript +const pi = 3.14; +pi = 5; // TypeError: Assignment to constant variable. +``` + +Зачем такие сложности? Почему бы не оставить только переменные? Даже если бы мы оставили только переменные, то это не отменяет того факта, что они часто использовались бы как константы, более того, код на JavaScript можно и идиоматично писать без использования переменных вообще. Посмотрите на пример из [реального кода Хекслета](https://github.com/Hexlet/hexlet-exercise-kit/blob/main/import-documentation/index.js). На текущем этапе вы его вряд ли поймете, но попробуйте посчитать количество констант и переменных внутри него, вы увидите, что здесь ровно одна переменная, и целая куча констант. + +Константы значительно проще для анализа, когда мы видим константу в коде, то нам сразу понятно, что ее значение всегда остается прежним. При использовании констант отсутствует понятие времени. С переменными все не так, мы не можем быть уверены в их значении, приходится анализировать весь код, чтобы понять, как они могли измениться. + +Переменные жизненно необходимы только в одном случае (во всех остальных гарантировано можно обойтись без них) - при работе с циклами, до которых мы ещё дойдем. + +В дальнейшем мы будем предпочитать константы и использовать переменные только тогда, когда без них никак. diff --git a/modules/30-variables/23-constants/ru/data.yml b/modules/30-variables/23-constants/ru/data.yml new file mode 100644 index 0000000..3e7b77e --- /dev/null +++ b/modules/30-variables/23-constants/ru/data.yml @@ -0,0 +1,6 @@ +name: Константы +tips: + - > + [const](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const) + - > + [TypeError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypeError) diff --git a/modules/30-variables/25-interpolation/ru/EXERCISE.md b/modules/30-variables/25-interpolation/ru/EXERCISE.md new file mode 100644 index 0000000..2acc54b --- /dev/null +++ b/modules/30-variables/25-interpolation/ru/EXERCISE.md @@ -0,0 +1,6 @@ + +Выведите на экран строку `Do you want to eat,
+Do you want to eat, Arya? +diff --git a/modules/30-variables/25-interpolation/ru/README.md b/modules/30-variables/25-interpolation/ru/README.md new file mode 100644 index 0000000..5f31fd9 --- /dev/null +++ b/modules/30-variables/25-interpolation/ru/README.md @@ -0,0 +1,34 @@ + +В уроке про конкатенацию перед нами стояла задача создать заголовок письма из двух констант и знаков препинания. Вы, скорее всего, решили задачу так: + +```javascript +const firstName = 'Joffrey'; +const greeting = 'Hello'; + +console.log(greeting + ', ' + firstName + '!'); +// => Hello, Joffrey! +``` + +Это довольно простой случай, но даже здесь нужно приложить усилия, чтобы увидеть, какая в итоге получится строка. Нужно следить за несколькими кавычками и пробелами, и без вглядывания не понять, где что начинается и кончается. + +Есть другой, более удобный и изящный способ решения той же задачи — **интерполяция**. Вот, как это выглядит: + +```javascript +const firstName = 'Joffrey'; +const greeting = 'Hello'; + +// Обратите внимание на ограничители строки, это бектики +// Интерполяция не работает с одинарными и двойными кавычками +console.log(`${greeting}, ${firstName}!`); +// => Hello, Joffrey! +``` + +https://replit.com/@hexlet/js-basics-interpolation + +Мы просто создали одну строку и «вставили» в неё в нужные места константы с помощью знака доллара и фигурных скобок `${ }`. Получился как будто бланк, куда внесены нужные значения. И нам не нужно больше заботиться об отдельных строках для знаков препинания и пробелов — все эти символы просто записаны в этой строке-шаблоне. + +В одной строке можно делать сколько угодно подобных блоков. + +Интерполяция работает только со строками в [бэктиках](https://ru.wikipedia.org/wiki/Машинописный_обратный_апостроф). Это символ `. + +Почти во всех языках интерполяция предпочтительнее конкатенации для объединения строк. Строка при этом получается склеенная, и внутри неё хорошо просматриваются пробелы и другие символы. Во-первых, интерполяция позволяет не путать строки с числами (из-за знака +), а во-вторых, так гораздо проще (после некоторой практики) понимать строку целиком. diff --git a/modules/30-variables/25-interpolation/ru/data.yml b/modules/30-variables/25-interpolation/ru/data.yml new file mode 100644 index 0000000..20b3444 --- /dev/null +++ b/modules/30-variables/25-interpolation/ru/data.yml @@ -0,0 +1,10 @@ +name: Интерполяция +tips: + - > + [Шаблонные + строки](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/template_strings) +definitions: + - name: Интерполяция + description: >- + способ соединения строк через вставку значений переменных в строку-шаблон + с помощью фигурных скобок. Например, `` `Hi, ${name}!` ``. diff --git a/modules/30-variables/30-symbols/ru/EXERCISE.md b/modules/30-variables/30-symbols/ru/EXERCISE.md new file mode 100644 index 0000000..d79f9e0 --- /dev/null +++ b/modules/30-variables/30-symbols/ru/EXERCISE.md @@ -0,0 +1,2 @@ + +Выведите на экран последний символ строки, находящейся в константе `name` diff --git a/modules/30-variables/30-symbols/ru/README.md b/modules/30-variables/30-symbols/ru/README.md new file mode 100644 index 0000000..6bc82cc --- /dev/null +++ b/modules/30-variables/30-symbols/ru/README.md @@ -0,0 +1,50 @@ + +Иногда нужно получить один символ из строки. Например, если сайт знает имя и фамилию пользователя, и в какой-то момент требуется вывести эту информацию в формате *A. Ivanov*, то нужно взять первый символ из имени. + +```javascript +const firstName = 'Tirion'; + +console.log(firstName[0]); // => T +``` + +Квадратные скобки с цифрой — это специальный синтаксис извлечения символа из строки. Цифра называется **индексом** — позицией символа внутри строки. Индексы начинаются с 0 почти во всех языках программирования — поэтому, чтобы получить первый символ, нужно указать индекс `0`. Индекс последнего элемента равен длине строки минус единица: + +```javascript +// Длина строки 6, поэтому последний индекс — это 5 +const firstName = 'Tirion'; + +console.log(firstName[5]); // => n +``` + +Вопрос на самопроверку. Что выведет этот код? + +``` +const magic = '\nyou'; +console.log(magic[1]); // => ? +``` + +
+First: N +Last: t ++ +Постарайтесь создать только одну константу, в которую сразу запишется нужный текст перед печатью на экран. В этом уроке мы отрабатываем умение собирать составное выражение. diff --git a/modules/35-calling-functions/150-calling-functions-expression/ru/README.md b/modules/35-calling-functions/150-calling-functions-expression/ru/README.md new file mode 100644 index 0000000..9ab6e4f --- /dev/null +++ b/modules/35-calling-functions/150-calling-functions-expression/ru/README.md @@ -0,0 +1,55 @@ + +В программировании выражение – нечто, возвращающее результат, который можно использовать. Мы уже знаем достаточно много о выражениях и о принципах их построения. Математические операции (сложение, вычитание), строковые операции (конкатенация) – все это выражения: + +```javascript +1 + 5 * 3; +'Hex' + 'Let'; +// Переменные могут быть частью выражения +rate * 5; +``` + +Особенность выражений в том, что они возвращают результат, который можно, например, присвоить константе или вывести на экран. Например: + +```javascript +// Тут выражение это 1 + 5 +const sum = 1 + 5; +console.log(1 + 5); +``` + +Но не все в программировании является выражением. Определение переменной – это инструкция, она не может быть частью выражения. То есть такой код выдаст ошибку: + +```javascript +// Бессмысленный код, который не сработает +10 + const sum = 1 + 5; +``` + +Почему об этом важно знать? Как вы увидите дальше, выражения можно комбинировать, получая все более сложное поведение в самых неожиданных местах и самым неожиданным образом. Вы будете лучше понимать, как можно соединять части кода, чтобы получить нужный результат. + +Поговорим о функциях. Вызов функции - это выражение или нет? Мы знаем, что функции возвращают результат, то есть да, они выражения. Из этого автоматически следует много интересного. Например, мы можем использовать вызов функции прямо в математических операциях. Вот как можно получить индекс последнего символа в слове: + +```javascript +import { length } from 'hexlet-basics/string'; + +const name = 'JavaScript'; +// Индексы начинаются с нуля +// Вызов метода и вычитание вместе! +const lastIndex = length(name) - 1; +console.log(lastIndex); // 9 +``` + +В этом коде нет нового синтаксиса. Мы всего лишь соединили уже известные части, опираясь на их природу. Можно пойти еще дальше: + +```javascript +console.log(length(name) - 1); // 9 +``` + +Все это справедливо для любых функций, например строковых: + +```javascript +import { length } from 'hexlet-basics/string'; + +const name = 'JavaScript'; +// Используется интерполяция +console.log(`Последний символ: ${name[length(name) - 1]}`); +// 'Последний символ: t' +``` diff --git a/modules/35-calling-functions/150-calling-functions-expression/ru/data.yml b/modules/35-calling-functions/150-calling-functions-expression/ru/data.yml new file mode 100644 index 0000000..bad9134 --- /dev/null +++ b/modules/35-calling-functions/150-calling-functions-expression/ru/data.yml @@ -0,0 +1,6 @@ +name: Вызов функции — выражение +definitions: + - name: Выражение + description: > + последовательность действий над данными, приводящая к каком-то результату, + который можно использовать. diff --git a/modules/35-calling-functions/180-variadic-parameters/ru/EXERCISE.md b/modules/35-calling-functions/180-variadic-parameters/ru/EXERCISE.md new file mode 100644 index 0000000..269f1ff --- /dev/null +++ b/modules/35-calling-functions/180-variadic-parameters/ru/EXERCISE.md @@ -0,0 +1,2 @@ + +Посчитайте программно (а не в голове) минимальное число среди 3, 10, 22, -3, 0 — и выведите его на экран. Воспользуйтесь функцией `Math.min()`, которая работает аналогично `Math.max()`. diff --git a/modules/35-calling-functions/180-variadic-parameters/ru/README.md b/modules/35-calling-functions/180-variadic-parameters/ru/README.md new file mode 100644 index 0000000..b1ed3e5 --- /dev/null +++ b/modules/35-calling-functions/180-variadic-parameters/ru/README.md @@ -0,0 +1,18 @@ + +Интересная особенность некоторых функций — принимать переменное число параметров. Речь не идет о значениях по умолчанию. Посмотрите на этот пример: + +```javascript +Math.max(1, 10, 3); // 10 +``` + +Функция `Math.max()` находит максимальное значение среди переданных параметров. Как вы думаете, сколько параметров она ожидает на вход? Если открыть документацию этой функции, то мы увидим странную конструкцию: + + ``` + Math.max([value1[, value2[, ...]]]) + ``` + + Такая запись говорит о том, что эта функция принимает на вход любое число параметров (и даже может быть вызвана без них). Необязательность передаваемых параметров описывается скобками *[ ]*, точно так же описываются и опциональные параметры, у которых есть значения по умолчанию. Возможность передачи любого числа параметров зашита в этой части *[, ...]*. + + ```javascript + Math.max(1, -3, 2, 3, 2); // 3 + ``` diff --git a/modules/35-calling-functions/180-variadic-parameters/ru/data.yml b/modules/35-calling-functions/180-variadic-parameters/ru/data.yml new file mode 100644 index 0000000..b7487ae --- /dev/null +++ b/modules/35-calling-functions/180-variadic-parameters/ru/data.yml @@ -0,0 +1,8 @@ +name: Функции с переменным числом параметров +tips: + - > + [Пример функции с переменным числом + параметров](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/max) +definitions: + - name: Аргумент по умолчанию + description: необязательный аргумент функции. diff --git a/modules/35-calling-functions/270-deterministic/ru/EXERCISE.md b/modules/35-calling-functions/270-deterministic/ru/EXERCISE.md new file mode 100644 index 0000000..2492674 --- /dev/null +++ b/modules/35-calling-functions/270-deterministic/ru/EXERCISE.md @@ -0,0 +1,8 @@ + +Функция `Math.random()` возвращает случайное число от 0 до 1 с большим количеством знаков после запятой. Но в реальных задачах бывает нужно получать случайные целые числа, например, в диапазоне от 0 до 10. Реализуйте код, который печатает на экран именно такие числа. Для этой задачи вам понадобятся функции [Math.random()](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Math/random) и [Math.round()](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Math/round) + +Попробуйте решить это задание в одну строчку + +## Алгоритм + +Так как `Math.random()` возвращает числа в диапазоне от 0 до 1, то чтобы получить числа от 0 до 10, нам нужно выполнить умножение на 10. Затем получившиеся число округляется и так мы получаем то, что нужно. diff --git a/modules/35-calling-functions/270-deterministic/ru/README.md b/modules/35-calling-functions/270-deterministic/ru/README.md new file mode 100644 index 0000000..07ab4af --- /dev/null +++ b/modules/35-calling-functions/270-deterministic/ru/README.md @@ -0,0 +1,22 @@ + +Независимо от того, какой язык программирования используется, функции внутри него обладают некоторыми фундаментальными свойствами. Зная эти свойства, легче прогнозировать поведение функций, способы их тестирования и место их использования. К таким свойствам относится детерминированность. Функция называется детерминированной тогда, когда для одних и тех же входных параметров она возвращает один и тот же результат. Например, функция, считающая количество символов, детерминированная: + +```javascript +import { length } from 'hexlet-basics/string'; + +length('hexlet'); // 6 +length('hexlet'); // 6 + +length('wow'); // 3 +length('wow'); // 3 +``` + +Сколько бы раз мы ни вызывали эту функцию, передавая туда значение `'hexlet'`, она всегда вернет `6`. В свою очередь функция, возвращающая случайное число, не является детерминированной, так как у одного и того же входа (даже если он пустой, то есть параметры не принимаются) мы получим всегда разный результат. Насколько он разный - не важно, даже если хотя бы один из миллиона вызовов вернет что-то другое, эта функция автоматически считается недетерминированной. + +```javascript +// Функция, возвращающая случайное число +Math.random(); // 0.09856613113197676 +Math.random(); // 0.8839904367241888 +``` + +Зачем это нужно знать? Детерминированность серьезно влияет на многие аспекты. Детерминированные функции удобны в работе, их легко оптимизировать, легко тестировать. Если есть возможность сделать функцию детерминированной, то лучше ее такой и сделать diff --git a/modules/35-calling-functions/270-deterministic/ru/data.yml b/modules/35-calling-functions/270-deterministic/ru/data.yml new file mode 100644 index 0000000..f863825 --- /dev/null +++ b/modules/35-calling-functions/270-deterministic/ru/data.yml @@ -0,0 +1,10 @@ +name: Детерминированность +tips: + - > + [Детерминированные + функции](https://ru.wikipedia.org/wiki/Чистота_функции#Детерминированность_функции) +definitions: + - name: Побочный эффект + description: >- + действие, которое изменяет внешнее окружение (среду выполнения). Например, + вывод на экран или отправка письма. diff --git a/modules/35-calling-functions/350-stdlib/ru/EXERCISE.md b/modules/35-calling-functions/350-stdlib/ru/EXERCISE.md new file mode 100644 index 0000000..390fc48 --- /dev/null +++ b/modules/35-calling-functions/350-stdlib/ru/EXERCISE.md @@ -0,0 +1,8 @@ + +Оператор `typeof` позволяет определить тип передаваемого операнда. Название типа возвращается в виде строки. Например, вызов `typeof 'go go go'` вернёт строку `'string'` (number — число). + +```javascript +console.log(typeof 3); // => 'number' +``` + +Выведите на экран тип значения константы `motto`. diff --git a/modules/35-calling-functions/350-stdlib/ru/README.md b/modules/35-calling-functions/350-stdlib/ru/README.md new file mode 100644 index 0000000..4546b78 --- /dev/null +++ b/modules/35-calling-functions/350-stdlib/ru/README.md @@ -0,0 +1,14 @@ + +JavaScript, как и любой другой язык, поставляется с набором полезных функций. Все вместе они составляют так называемую **стандартную библиотеку**. В неё обычно входят тысячи функций, которые невозможно выучить — этого и не нужно делать. Подразумевается, что любой программист знает, где искать документацию по ним и примерно представляет себе, чего он хочет достичь. А дальше — дело техники. Если отнять у программистов интернет, то большинство не сможет ничего запрограммировать. + +Для новичков эта информация часто выглядит так: «Сходи туда, не знаю куда, принеси то, не знаю что». То есть непонятно, как узнавать про эти функции, когда ты ничего не знаешь вообще. Как ни странно, не существует способа раз и навсегда познать всё, что нужно познать. Любой разработчик в процессе своего профессионального взросления знакомится со всё более интересными функциями, решающими его задачи более элегантно, и таким образом пополняет свой арсенал. + +Вот некоторые советы, как узнавать о новых функциях: + +* Всегда чётко отслеживайте, с чем вы сейчас работаете (какой тип данных). Почти всегда вы найдете необходимую функцию в соответствующем разделе документации — например, для работы со строками нужно изучать строковые функции. +* Периодически открывайте раздел со стандартными функциями по изучаемой тематике и просто пробегайтесь по ним, изучая сигнатуры и способы использования. +* Чаще читайте чужой код, особенно код библиотек, которые вы используете. Он весь доступен на GitHub. + +У JavaScript есть свои особенности по структуре стандартной библиотеки. Так как его код может исполняться в разных средах, таких как серверное окружение или браузер, то возможности стандартной библиотеки сильно зависят от варианта использования. Например, из браузера невозможно выполнять некоторые задачи, которые необходимо уметь выполнять на сервере. Документацию по серверной части необходимо смотреть на сайте https://nodejs.org. Серверные части стандартной библиотеки организованы в модули, у каждого модуля есть своя страница с описанием всех функций, находящихся внутри него. Например, модуль [fs](https://nodejs.org/api/fs.html) необходим для работы с файловой системой, через его функции происходит запись и чтение файлов. + +Если говорить про браузер, то там вообще мало что есть. По большей части это какие-то базовые функции, встроенные в сам язык — например те же [функции](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Math) для работы с математикой. Остальные возможности добавляются через использование сторонних библиотек. diff --git a/modules/35-calling-functions/350-stdlib/ru/data.yml b/modules/35-calling-functions/350-stdlib/ru/data.yml new file mode 100644 index 0000000..3466e74 --- /dev/null +++ b/modules/35-calling-functions/350-stdlib/ru/data.yml @@ -0,0 +1,13 @@ +name: Стандартная библиотека +tips: + - > + [Описание строковых + функций](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) + - > + [Как искать техническую + информацию](https://guides.hexlet.io/ru/how-to-search/) +definitions: + - name: Стандартная библиотека + description: >- + набор полезных функций, входящий в комплект поставки языка + программирования. diff --git a/modules/38-properties/100-properties-syntax/ru/EXERCISE.md b/modules/38-properties/100-properties-syntax/ru/EXERCISE.md new file mode 100644 index 0000000..85dabdd --- /dev/null +++ b/modules/38-properties/100-properties-syntax/ru/EXERCISE.md @@ -0,0 +1,2 @@ + +Напечатайте на экран длину строки `text`. diff --git a/modules/38-properties/100-properties-syntax/ru/README.md b/modules/38-properties/100-properties-syntax/ru/README.md new file mode 100644 index 0000000..49cd3ab --- /dev/null +++ b/modules/38-properties/100-properties-syntax/ru/README.md @@ -0,0 +1,37 @@ + +Данные, которыми мы оперируем в своих программах, могут обладать важными свойствами — например, у строк есть длина. Как вы увидите далее, это свойство очень важно для реализации алгоритмов, связанных с преобразованием строки (как пример — переворот строки). Как узнать длину строки? Во многих языках длина строки вычисляется с помощью специальной функции и выглядит это примерно так: + +```javascript +import { length } from 'hexlet-basics/string'; + +const name = 'Robb'; +console.log(length(name)); // => 4 +``` + +В JavaScript свойства встроены прямо в язык. Они указываются через точку сразу после переменной (или константы): + +```javascript +const name = 'Robb'; +const len = name.length; +console.log(len); // => 4 +``` + +https://replit.com/@hexlet/js-basics-properties-properties-syntax + +Свойства связаны с данными, у которых они берутся. Для примитивных типов все свойства описаны в документации, как например, у [строк](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/String). При этом у чисел вообще нет свойств. + +JavaScript позволяет обращаться к свойствам, которые не существуют (например, при опечатках). В таком случае их значением является `undefined`: + +```javascript +const name = 'Robb'; +console.log(name.whatIsThat); // => undefined +``` + +*Вопрос для самопроверки. Что распечатает код `console.log(name[name.length])` для `name`, определенного выше? Почему ответ такой?* + +
+First: N +Last: t ++ +Ваша задача извлечь эти символы из строки и вставить в `console.log()`, не используя промежуточные переменные. diff --git a/modules/38-properties/400-properties-expressions/ru/README.md b/modules/38-properties/400-properties-expressions/ru/README.md new file mode 100644 index 0000000..95a1b91 --- /dev/null +++ b/modules/38-properties/400-properties-expressions/ru/README.md @@ -0,0 +1,22 @@ + +Свойства и методы — такие же выражения, как переменные, константы или вызовы функции, а значит, их можно всячески комбинировать. + +Использование в операциях: + +```javascript +const name = 'Shaya'; +name.length + 5; // 10 +`hi, ${name.toUpperCase()}!`; // hi, SHAYA! +``` + +Использование в параметрах функций: + +```javascript +const name1 = 'Robb'; +const name2 = 'Shaya'; +console.log(name2.length); // => 5 +console.log(name2.toLowerCase()); // => shaya +console.log(Math.min(name1.length, name2.length)); // => 4 +``` + +https://replit.com/@hexlet/js-basics-properties-method diff --git a/modules/38-properties/400-properties-expressions/ru/data.yml b/modules/38-properties/400-properties-expressions/ru/data.yml new file mode 100644 index 0000000..9bada81 --- /dev/null +++ b/modules/38-properties/400-properties-expressions/ru/data.yml @@ -0,0 +1,9 @@ +name: Свойства и методы как выражения +tips: + - > + [немного о методе + .trim()](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/String/Trim) +definitions: + - name: Метод + description: | + это функция или процедура, принадлежащая какому-то классу или объекту. diff --git a/modules/38-properties/500-properties-chain-of-methods/ru/EXERCISE.md b/modules/38-properties/500-properties-chain-of-methods/ru/EXERCISE.md new file mode 100644 index 0000000..09ebc58 --- /dev/null +++ b/modules/38-properties/500-properties-chain-of-methods/ru/EXERCISE.md @@ -0,0 +1,5 @@ + +С помощью метода `slice()` получите часть предложения, записанного в константу `text`, c `5` по `15` символы включительно. Полученную подстроку обработайте методом `.trim()` и выведите на экран длину итоговой подстроки. Выполните эти методы подряд в цепочке без создания промежуточных переменных. + +* [slice()](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/String/slice) +* [trim()](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/String/Trim) diff --git a/modules/38-properties/500-properties-chain-of-methods/ru/README.md b/modules/38-properties/500-properties-chain-of-methods/ru/README.md new file mode 100644 index 0000000..ef6c4e5 --- /dev/null +++ b/modules/38-properties/500-properties-chain-of-methods/ru/README.md @@ -0,0 +1,50 @@ + +У чисел есть метод, который преобразует их в строку: + +```javascript +const peopleCount = 5; +peopleCount.toString(); // 5 +``` + +Попробуйте ответить на вопрос, заработает ли следующий код — и если да, то что он напечатает на экран? + +```javascript +const name = 'Tirion'; +console.log(name.length.toString()); +``` + +Синтаксис нескольких подряд идущих точек мы видим впервые, но все операции, которые здесь встречаются, нам знакомы. Всё, что произошло в этом коде — это объединение уже известных возможностей языка. Такое в программировании происходит довольно часто. Даже не зная синтаксиса, можно пробовать комбинировать различные подходы, и есть неплохая вероятность, что они заработают. + +Самый простой способ понять как работает этот код — разбить цепочку на отдельные операции: + +```javascript +const name = 'Tirion'; +const len = name.length; +console.log(len.toString()); +``` + +Эти примеры абсолютно эквивалентны. Мы можем выполнять операции последовательно с промежуточным созданием констант, а можем строить непрерывную цепочку из свойств и методов. В цепочках вычисления всегда идут слева направо. + +Ещё один пример для закрепления: + +```javascript +const name = 'Tirion'; +console.log(name.toUpperCase().toLowerCase()); +``` + +Подобный код требует небольших умственных усилий. Важно понимать, что `.toLowerCase()` применяется к результату вызова метода, который находится левее. А метод `toUpperCase()` возвращает строку. Новички часто делают ошибки в цепочках с методами, забывая ставить вызов: + +```javascript +const name = 'Tirion'; +// Этот код отработает неверно! +console.log(name.toUpperCase.toLowerCase()); +``` + +Продолжая эту идею, возможно строить бесконечно длинные (хотя, в данном случае, бесполезные) цепочки: + +```javascript +// Чему равен результат такого вызова? +console.log(name.toUpperCase().toLowerCase().length.toString().length); +``` + +*С функциями подобный трюк не сработает, так как при обычном использовании они вкладываются друг в друга f(f(f())), что значительно ухудшает анализ. Но это не значит, что нельзя сделать красиво — можно и даже нужно. В других языках это реализуется через композицию функций или пайплайн-оператор, который, кстати говоря, постепенно начинает использоваться и в самом JavaScript: https://github.com/tc39/proposal-pipeline-operator.* diff --git a/modules/38-properties/500-properties-chain-of-methods/ru/data.yml b/modules/38-properties/500-properties-chain-of-methods/ru/data.yml new file mode 100644 index 0000000..7d0b9a5 --- /dev/null +++ b/modules/38-properties/500-properties-chain-of-methods/ru/data.yml @@ -0,0 +1,6 @@ +name: Цепочка вызовов +tips: [] +definitions: + - name: Метод + description: | + это функция или процедура, принадлежащая какому-то классу или объекту. diff --git a/modules/40-define-functions/100-define-functions-syntax/ru/EXERCISE.md b/modules/40-define-functions/100-define-functions-syntax/ru/EXERCISE.md new file mode 100644 index 0000000..b378df5 --- /dev/null +++ b/modules/40-define-functions/100-define-functions-syntax/ru/EXERCISE.md @@ -0,0 +1,8 @@ + +Реализуйте функцию с именем `printMotto()`, которая выведет на экран фразу *Winter is coming*. + +```javascript +printMotto(); // => Winter is coming +``` + +В задачах, в которых нужно реализовать функцию, эту функцию вызывать не нужно. Вызывать функцию будут автоматизированные тесты, которые проверяют её работоспособность. Пример с вызовом выше показан только для того, чтобы вы понимали, как ваша функция будет использоваться. diff --git a/modules/40-define-functions/100-define-functions-syntax/ru/README.md b/modules/40-define-functions/100-define-functions-syntax/ru/README.md new file mode 100644 index 0000000..bc9d792 --- /dev/null +++ b/modules/40-define-functions/100-define-functions-syntax/ru/README.md @@ -0,0 +1,65 @@ + +Определение собственных функций значительно упрощает написание и поддержку программ. Функции позволяют объединять сложные (составные) операции в одну. Например, отправка письма на сайте - это достаточно сложный процесс, включающий в себя взаимодействие с внешними системами (интернет). Благодаря возможности определять функции, вся сложность может быть скрыта за одной простой функцией: + +```javascript +// Гипотетический пример +// Место откуда берется функция +import { send } from 'mailer'; + +const email = 'support@hexlet.io'; +const title = 'Помогите'; +const body = 'Я написал историю успеха, как я могу получить скидку?'; + +// Один маленький вызов — и много логики внутри +send(email, title, body); +``` + +Внутри себя подобный вызов выполняет довольно много логики. Соединяется с почтовым сервером, формирует правильный запрос на основе заголовка и тела сообщения, а затем все это отправляет, не забыв закрыть соединение. + +Создадим нашу первую функцию. Ее задача - вывести на экран приветствие: + +
Hello, Hexlet!+ +```javascript +// Определение функции +// Определение не вызывает и не выполняет функцию +// Мы лишь говорим, что теперь такая функция существует +const showGreeting = () => { + // Внутри тела отступ 2 пробела для удобства чтения + const text = 'Hello, Hexlet!'; + console.log(text); +} + +// Вызов функции +showGreeting(); // => Hello, Hexlet! +``` + +https://replit.com/@hexlet/js-basics-functions-define + +В отличие от обычных данных, функции выполняют действия, поэтому их имена практически всегда должны быть глаголами: «построить что-то», «нарисовать что-то», «открыть что-то». + +Всё, что описывается внутри фигурных скобок `{}`, называется телом функции. Внутри тела можно описывать любой код. Считайте, что это маленькая самостоятельная программа, набор произвольных инструкций. Тело выполняется ровно в тот момент, когда запускается функция. Причём каждый вызов функции запускает тело независимо от других вызовов. Кстати, тело может быть пустым: + +```javascript +// Минимальное определение функции +const noop = () => { + // Тут мог бы быть код, но его нет +} + +noop(); +``` + +Определение функции подозрительно похоже на создание константы. Действительно, в реальности, определение функции состоит из двух частей: собственно определения и присваивания константе: + +1. Определение: `() => { }` +2. Присваивание `const nameOfFunction = ...` + +Технически возможно создать функцию, которая просто определена, но ей невозможно воспользоваться, потому что нет имени: + +```javascript +() => { + // Работающий, но бесполезный код +}; +``` + +Понятие «создать функцию» имеет много синонимов: «реализовать», «определить» и даже «заимплементить» (от слова implement). Все они встречаются в повседневной практике на работе. diff --git a/modules/40-define-functions/100-define-functions-syntax/ru/data.yml b/modules/40-define-functions/100-define-functions-syntax/ru/data.yml new file mode 100644 index 0000000..22876b2 --- /dev/null +++ b/modules/40-define-functions/100-define-functions-syntax/ru/data.yml @@ -0,0 +1,5 @@ +name: Создание (определение) функций +tips: + - > + [Именование в + программировании](https://ru.hexlet.io/blog/posts/naming-in-programming) diff --git a/modules/40-define-functions/150-define-functions-return/ru/EXERCISE.md b/modules/40-define-functions/150-define-functions-return/ru/EXERCISE.md new file mode 100644 index 0000000..b9a0fac --- /dev/null +++ b/modules/40-define-functions/150-define-functions-return/ru/EXERCISE.md @@ -0,0 +1,7 @@ + +Реализуйте функцию `sayHurrayThreeTimes()`, которая возвращает строку 'hurray! hurray! hurray!'. + +```javascript +const hurray = sayHurrayThreeTimes(); +console.log(hurray); // => hurray! hurray! hurray! +``` diff --git a/modules/40-define-functions/150-define-functions-return/ru/README.md b/modules/40-define-functions/150-define-functions-return/ru/README.md new file mode 100644 index 0000000..3e27ee5 --- /dev/null +++ b/modules/40-define-functions/150-define-functions-return/ru/README.md @@ -0,0 +1,116 @@ + +Функции, которые мы определяли в предыдущих уроках, заканчивали свою работу тем, что печатали на экран какие-то данные: + +```javascript +const greeting = () => { + console.log('Hello, Hexlet!'); +}; +``` + +Пользы от таких функций не очень много, так как результатом их работы невозможно воспользоваться внутри программы. Рассмотрим это на примере. + +Возьмем задачу обработки электронной почты. Когда пользователь регистрируется на каком-то сайте, то он может ввести email любым способом: + +* Добавив случайно пробелы в начале или в конце `_support@hexlet.io__` +* Использовав буквы в разном регистре `SUPPORT@hexlet.io` + +Если мы сохраним его в таком виде в базу данных, то пользователь, скорее всего, не сможет войти на сайт, так как будет вбивать адрес без пробелов и используя другой регистр символов. Чтобы этого не произошло, email нужно подготовить к записи в базу, привести его к нижнему регистру и обрезать пробельные символы по краям строки. Вся задача решается в пару строчек: + +```javascript +const saveEmail = () => { + // В реальности email приходит из формы + const email = ' SuppORT@hexlet.IO'; + // обрезаем пробельные символы + const trimmedEmail = email.trim(); + const preparedEmail = trimmedEmail.toLowerCase(); + console.log(preparedEmail); + // здесь будет запись в базу данных +}; +``` + +Этот код стал возможен только благодаря возврату значения. Методы `trim()` и `toLowerCase()` ничего не печатают на экран (в консоль), они **возвращают** результат своей работы и поэтому мы можем записать его в константы. Если бы они вместо этого печатали на экран, мы бы не могли присвоить результат их работы константе. Как мы не можем сделать с определенной выше функцией `greeting()`: + +```javascript +const message = greeting(); +console.log(message); // => undefined +``` + +Изменим функцию `greeting()` таким образом, чтобы она начала возвращать данные, вместо их печати. Для этого нам понадобится выполнить возврат вместо печати на экран + +```javascript +const greeting = () => { + return 'Hello, Hexlet!'; +}; +``` + +`return` – особая инструкция, которая берёт выражение, записанное справа, и отдаёт его наружу, тому коду, который вызвал функцию. Как только JavaScript натыкается на `return`, выполнение функции на этом завершается. + +```javascript +// Теперь мы можем использовать результат работы функции +const message = greeting(); +console.log(message); // => Hello, Hexlet! +// И даже выполнить какие-то действия над результатом +console.log(message.toUpperCase()); // => HELLO, HEXLET! +``` + +Любой код после `return` не выполняется: + +```javascript +const greetingWithCodeAfterReturn = () => { + return 'Hello, Hexlet!'; + console.log('Я никогда не выполнюсь'); +}; +``` + +Даже если функция возвращает данные, это не ограничивает её в том, что она печатает. Кроме возврата данных мы можем и печатать: + +```javascript +const greetingWithReturnAndPrinting = () => { + console.log('Я появлюсь в консоли'); + return 'Hello, Hexlet!'; +}; + +// И напечатает текст на экран и вернет значение +const message = greetingWithReturnAndPrinting (); +``` + +Возвращать можно не только конкретное значение. Так как `return` работает с выражениями, то справа от него может появиться почти все что угодно. Здесь нужно руководствоваться принципами читаемости кода: + +```javascript +const greeting = () => { + const message = 'Hello, Hexlet!'; + return message; +}; +``` + +Здесь мы не возвращаем переменную, возвращается всегда значение, которое находится в этой переменной. Ниже пример с вычислениями: + +```javascript +const doubleFive = () => { + // или return 5 + 5 + const result = 5 + 5; + return result; +}; +``` + +Вопрос на самопроверку. Что вернет вызов, определенной ниже, функции `run()`? + +```javascript +// Определение +const run = () => { + return 5; + return 10; +}; + +// Что будет выведено на экран? +console.log(run()); +``` + +
false+ +https://replit.com/@hexlet/js-basics-logic-bool-type + +А теперь проверим ребенка, которому полгода: + +```javascript +console.log(isInfant(0.5)); +``` + +
truediff --git a/modules/45-logic/10-bool-type/ru/data.yml b/modules/45-logic/10-bool-type/ru/data.yml new file mode 100644 index 0000000..0140ba5 --- /dev/null +++ b/modules/45-logic/10-bool-type/ru/data.yml @@ -0,0 +1,8 @@ +name: Логический тип +tips: + - > + [Boolean в + JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean) +definitions: + - name: Логический тип (boolean) + description: 'тип данных с двумя возможными значениями: true (истина) и false (ложь).' diff --git a/modules/45-logic/15-predicates/ru/EXERCISE.md b/modules/45-logic/15-predicates/ru/EXERCISE.md new file mode 100644 index 0000000..7cc71d7 --- /dev/null +++ b/modules/45-logic/15-predicates/ru/EXERCISE.md @@ -0,0 +1,9 @@ + +Напишите функцию `isMister()`, которая принимает строку и проверяет, является ли она словом `'Mister'`. + +Примеры вызова: + +```javascript +isMister('Mister'); // true +isMister('Miss'); // false +``` diff --git a/modules/45-logic/15-predicates/ru/README.md b/modules/45-logic/15-predicates/ru/README.md new file mode 100644 index 0000000..2de8be5 --- /dev/null +++ b/modules/45-logic/15-predicates/ru/README.md @@ -0,0 +1,33 @@ + +Вспомним функцию `isInfant()` из прошлого урока: + +```javascript +const isInfant = (age) => age < 1; +console.log(isInfant(3)); +``` +
false+ +https://replit.com/@hexlet/js-basics-logic-bool-type + +Подобные функции называют предикатами. Функции-предикаты (или функции-вопросы) отвечают на какой-то вопрос и всегда (без исключений!) возвращают либо `true`, либо `false`. + +Предикаты во всех языках принято именовать особым образом для простоты анализа. В JavaScript предикаты, как правило, начинаются с префикса `is`, `has` или `can`, но не ограничены этими словами. Примеры: + + * `isInfant()` — «младенец ли?» + * `hasChildren()` — «есть ли дети?» + * `isEmpty()` — «пустой ли?» + * `hasErrors()` — «есть ли ошибки?» + +Функция может считаться предикатом **только** если она возвращает boolean. + +--- + +Давайте напишем ещё одну функцию-предикат. Она принимает строку и проверяет, является ли она словом `'Castle'`: + +```javascript +const isCastle = (type) => type === 'Castle'; + +console.log(isCastle('Sea')); +``` + +
falsediff --git a/modules/45-logic/15-predicates/ru/data.yml b/modules/45-logic/15-predicates/ru/data.yml new file mode 100644 index 0000000..2980e9f --- /dev/null +++ b/modules/45-logic/15-predicates/ru/data.yml @@ -0,0 +1,8 @@ +name: Предикаты +tips: + - > + [Именование в + программировании](https://ru.hexlet.io/blog/posts/naming-in-programming) +definitions: + - name: Предикат + description: выражение, отвечающее на вопрос «да» или «нет» с помощью типа boolean. diff --git a/modules/45-logic/20-logic-combine-expressions/ru/EXERCISE.md b/modules/45-logic/20-logic-combine-expressions/ru/EXERCISE.md new file mode 100644 index 0000000..1cf0ce5 --- /dev/null +++ b/modules/45-logic/20-logic-combine-expressions/ru/EXERCISE.md @@ -0,0 +1,7 @@ + +Реализуйте функцию, которая проверяет формат указанного телефона. Если телефон начинается с *+*, значит это международный формат. + +```javascript +isInternationalPhone('89602223423'); // false +isInternationalPhone('+79602223423'); // true +``` diff --git a/modules/45-logic/20-logic-combine-expressions/ru/README.md b/modules/45-logic/20-logic-combine-expressions/ru/README.md new file mode 100644 index 0000000..54c8646 --- /dev/null +++ b/modules/45-logic/20-logic-combine-expressions/ru/README.md @@ -0,0 +1,67 @@ + +Логические операции — это выражения. Значит, логические операции можно комбинировать с другими выражениями. + +Например, мы хотим проверить чётность числа, то есть кратность двум. В программировании используют такой подход: + +* проверяют остаток от деления на 2: + * если остаток 0, то число было чётным + * если остаток не 0, то число было нечётным + +Остаток от деления — простая, но очень важная концепция в арифметике, алгебре, и даже в теории чисел и криптографии. Идея проста: нужно разделить число на несколько равных групп, и если в конце что-то останется — это и есть остаток от деления. + +Делим конфеты поровну между людьми: + +- 7 конфет, 2 человека: 2 x 3 + **остаток 1**. + Значит, 7 не кратно 2. +- 21 конфету, 3 человека: 3 x 7 + **остаток 0**. + Значит, 21 кратно 3. +- 19 конфет, 5 человек: 5 x 3 + **остаток 4**. + Значит, 19 не кратно 5. + +Оператор `%` вычисляет остаток от деления (не путайте с делением): + +```javascript +7 % 2; // 1 +21 % 3; // 0 +19 % 5; // 4 + +// Проверка четности + +10 % 2 // 10 чётное, так как остаток 0 +9 % 2 // 9 нечётное, так как остаток 1 +``` + +Напишем функцию проверки чётности: + +```javascript +const isEven = (number) => number % 2 === 0; + +isEven(10); // true +isEven(3); // false +``` + +В одном выражении мы скомбинировали логический оператор `===` (проверка равенства) и арифметический оператор `%`. + +Приоритет арифметических операций выше логических. Значит, сначала вычисляется арифметическое выражение `number % 2`, затем результат участвует в логическом сравнении. + +Словами это можно расшифровать так: *«вычислить остаток от деления числа `number` на 2 и сравнить, равен ли остаток нулю; затем вернуть результат проверки равенства»*. + +Другой пример: напишем функцию, которая принимает строку и проверяет, заглавная ли первая буква. + +Алгоритм: + +1. Получим и запишем в переменную первый символ из строки-параметра +2. Сравним, равен ли символ своей большой (заглавной) версии +3. Вернём результат + +```javascript +const isFirstLetterInUpperCase = (string) => { + const firstLetter = string[0]; + return firstLetter.toUpperCase() === firstLetter; +}; + +isFirstLetterInUpperCase('marmont'); // false +isFirstLetterInUpperCase('Robb'); // true +``` + +https://replit.com/@hexlet/js-basics-logica-operations diff --git a/modules/45-logic/20-logic-combine-expressions/ru/data.yml b/modules/45-logic/20-logic-combine-expressions/ru/data.yml new file mode 100644 index 0000000..e38a0ed --- /dev/null +++ b/modules/45-logic/20-logic-combine-expressions/ru/data.yml @@ -0,0 +1,9 @@ +name: Комбинирование логических операций +tips: + - | + [Выражение](https://ru.wikipedia.org/wiki/Выражение_(информатика)) +definitions: + - name: Выражение + description: > + последовательность действий над данными, приводящая к каком-то результату, + который можно использовать. diff --git a/modules/45-logic/25-logical-operators/ru/EXERCISE.md b/modules/45-logic/25-logical-operators/ru/EXERCISE.md new file mode 100644 index 0000000..4107661 --- /dev/null +++ b/modules/45-logic/25-logical-operators/ru/EXERCISE.md @@ -0,0 +1,19 @@ + +Реализуйте функцию `isLeapYear()`, которая определяет, является ли год високосным или нет. Год будет високосным, если он кратен (то есть делится без остатка) 400 или он одновременно кратен 4 и не кратен 100. Как видите, в определении уже заложена вся необходимая логика, осталось только переложить её на код: + +```javascript +isLeapYear(2018); // false +isLeapYear(2017); // false +isLeapYear(2016); // true +``` + +Кратность можно проверять так: + +```javascript +// % - возвращает остаток от деления левого операнда на правый +// Проверяем что number кратен 10 +number % 10 === 0 + +// Проверяем что number не кратен 10 +number % 10 !== 0 +``` diff --git a/modules/45-logic/25-logical-operators/ru/README.md b/modules/45-logic/25-logical-operators/ru/README.md new file mode 100644 index 0000000..1c370d6 --- /dev/null +++ b/modules/45-logic/25-logical-operators/ru/README.md @@ -0,0 +1,99 @@ + +Логические выражения могут объединяться друг с другом, создавая все более хитрые проверки. Хороший пример: проверка пароля. Как вы знаете, некоторые сайты при регистрации хотят пароль от 8 до 20 символов в длину. Честно говоря, это странное ограничение, но что поделать. В математике мы бы написали `8 < x < 20` (где `x` это длина конкретного пароля), но в JavaScript такой трюк не пройдет. Нам придётся сделать два отдельных логических выражения и соединить их специальным оператором «И»: + +``` +Пароль длиннее 8 символов **И** пароль короче 20 символов. +``` + +Вот функция, которая принимает пароль и говорит, соответствует ли он условиям, или не соответствует: + +```javascript +const isStrongPassword = (password) => { + const length = password.length; + return length > 8 && length < 20; +}; + +isStrongPassword('qwerty'); // false +isStrongPassword('qwerty1234'); // true +isStrongPassword('zxcvbnmasdfghjkqwertyui'); // false +``` + +`&&` - означает «И» (в математической логике это называют конъюнкцией). Всё выражение считается истинным только в том случае, когда истинен каждый операнд — каждое из составных выражений. Иными словами, `&&` означает «и то, и другое». + +Приоритет этого оператора ниже, чем приоритет операторов сравнения, поэтому выражение отрабатывает правильно без скобок. + +Кроме `&&`, часто используется оператор `||` — «ИЛИ» (дизъюнкция). Он означает «или то, или другое, или оба». Операторы можно комбинировать в любом количестве и любой последовательности, но когда одновременно встречаются `&&` и `||`, то приоритет лучше задавать скобками. Ниже пример расширенной функции определения корректности пароля: + +```javascript +const hasSpecialChars = (str) => /* проверяет содержание специальных символов в строке */; + +const hasCapitalChars = (str) => /* проверяет содержание заглавных букв в строке */ + +const isStrongPassword = (password) => { + const length = password.length; + // Скобки задают приоритет. Понятно что к чему относится. + return length > 8 && (hasSpecialChars(password) || hasCapitalChars(password)); +}; +``` + +Другой пример. Мы хотим купить квартиру, которая удовлетворяет условиям: площадь от 100 кв. метров и больше на любой улице **ИЛИ** площадь от 80 кв. метров и больше, но на центральной улице `Main Street`. + +Напишем функцию, проверяющую квартиру. Она принимает два аргумента: площадь (число) и название улицы (строку): + +```javascript +const isGoodApartment = (area, street) => { + // Через переменную, чтобы функция была не слишком длинной + const result = area >= 100 || (area >= 80 && street === 'Main Street'); + return result; +}; + +isGoodApartment(91, 'Queens Street'); // false +isGoodApartment(78, 'Queens Street'); // false +isGoodApartment(70, 'Main Street'); // false + +isGoodApartment(120, 'Queens Street'); // true +isGoodApartment(120, 'Main Street'); // true +isGoodApartment(80, 'Main Street'); // true +``` + +https://replit.com/@hexlet/js-basics-logical-operators + +Область математики, в которой изучаются логические операторы, называется булевой алгеброй. Ниже показаны «таблицы истинности» — по ним можно определить, каким будет результат применения оператора: + +## И `&&` + +| A | B | A && B | +|-------| ------|----------| +| TRUE | TRUE | **TRUE** | +| TRUE | FALSE | FALSE | +| FALSE | TRUE | FALSE | +| FALSE | FALSE | FALSE | + +Пара примеров: + +```javascript +// true && true; +3 > 2 && 'wow'.startsWith('w'); // true + +// true && false; +'start' === 'start' && 8 < 3; // false +``` + +## ИЛИ `||` + +| A | B | A || B | +|-------|-------|----------| +| TRUE | TRUE | **TRUE** | +| TRUE | FALSE | **TRUE** | +| FALSE | TRUE | **TRUE** | +| FALSE | FALSE | FALSE | + +Пара примеров: + +```javascript +// true || true; +3 > 2 || 'wow'.startsWith('w'); // true + +// false || false; +'start' === 'Start' || 3 < 3; // false +``` diff --git a/modules/45-logic/25-logical-operators/ru/data.yml b/modules/45-logic/25-logical-operators/ru/data.yml new file mode 100644 index 0000000..cb8576a --- /dev/null +++ b/modules/45-logic/25-logical-operators/ru/data.yml @@ -0,0 +1,13 @@ +name: Логические операторы +tips: + - | + [Булева алгебра](https://ru.wikipedia.org/wiki/Булева_алгебра) + - | + [Конъюнкция](https://ru.wikipedia.org/wiki/Конъюнкция) + - | + [Дизъюнкция](https://ru.wikipedia.org/wiki/Дизъюнкция) +definitions: + - name: Логические операторы + description: >- + операторы «И» (&&), «ИЛИ» (||), позволяющие создавать составные логические + условия. diff --git a/modules/45-logic/28-logical-negation/ru/EXERCISE.md b/modules/45-logic/28-logical-negation/ru/EXERCISE.md new file mode 100644 index 0000000..00102e8 --- /dev/null +++ b/modules/45-logic/28-logical-negation/ru/EXERCISE.md @@ -0,0 +1,30 @@ + +В этом уроке вам нужно будет реализовать две функции `isPalindrome()` и `isNotPalindrome()` + +1. Функция `isPalindrome()` определяет, является ли слово палиндромом или нет. Палиндром это слово, которое читается одинаково в обоих направлениях. + + ```javascript + isPalindrome('шалаш'); // true + isPalindrome('ага'); // true + isPalindrome('хекслет'); // false + + // Слова в функцию могут быть переданы в любом регистре + // Поэтому сначала нужно привести слово в нижний регистр word.toLowerCase() + isPalindrome('Ага'); // true + ``` + + Для определения палиндрома необходимо перевернуть строку и сравнить ее с исходной. Для этого воспользуйтесь функцией `reverse()` + + ```javascript + reverse('мама'); // амам + ``` + +2. Функция `isNotPalindrome()` проверяет что слово НЕ является палиндромом: + + ```javascript + isNotPalindrome('шалаш'); // false + isNotPalindrome('ага'); // false + isNotPalindrome('хекслет'); // true + ``` + + Для этого, вызовите функцию `isPalindrome()` внутри `isNotPalindrome()` и примените отрицание. diff --git a/modules/45-logic/28-logical-negation/ru/README.md b/modules/45-logic/28-logical-negation/ru/README.md new file mode 100644 index 0000000..69dc65f --- /dev/null +++ b/modules/45-logic/28-logical-negation/ru/README.md @@ -0,0 +1,25 @@ + +Наряду с конъюнкцией (И) и дизъюнкцией (ИЛИ), часто используется операция «отрицание». Отрицание меняет логическое значение на противоположное. В программировании ему соответствует унарный оператор `!`. + +Если есть функция, проверяющая чётность числа, то с помощью отрицания можно выполнить проверку нечётности: + +```javascript +const isEven = (number) => number % 2 === 0; + +isEven(10); // true +!isEven(10); // false +``` + +https://replit.com/@hexlet/js-basics-logical-negation + +То есть мы просто добавили `!` слева от вызова функции и получили обратное действие. + +Отрицание — мощный инструмент, который позволяет лаконично выражать задуманные правила в коде без необходимости писать новые функции. + +А что если написать так `!!isEven(10)`? Внезапно, но код сработает. В логике двойное отрицание подобно отсутствию отрицания вообще. + +```javascript +isEven(10); // true +!isEven(10); // false +!!isEven(10); // true +``` diff --git a/modules/45-logic/28-logical-negation/ru/data.yml b/modules/45-logic/28-logical-negation/ru/data.yml new file mode 100644 index 0000000..b892f6d --- /dev/null +++ b/modules/45-logic/28-logical-negation/ru/data.yml @@ -0,0 +1,9 @@ +name: Отрицание +tips: + - | + [Законы Де Моргана](https://ru.wikipedia.org/wiki/Законы_де_Моргана) +definitions: + - name: Отрицание + description: > + логическая операция, которая меняет логическое значение на + противоположное. diff --git a/modules/45-logic/70-logical-expressions/ru/EXERCISE.md b/modules/45-logic/70-logical-expressions/ru/EXERCISE.md new file mode 100644 index 0000000..3bdc0ce --- /dev/null +++ b/modules/45-logic/70-logical-expressions/ru/EXERCISE.md @@ -0,0 +1,18 @@ + +Реализуйте функцию `getLetter()`, которая извлекает из переданной строки указанный символ (по порядковому номеру, а не по его индексу) и возвращает его наружу. Если такого символа нет, то функция возвращает пустую строку. + +Примеры вызова: + +```javascript +const name = 'Hexlet'; + +// Обычное обращение возвращает undefined +name[10]; // undefined + +// 11 символ соответствует 10 индексу +getLetter(name, 11); // '' + +getLetter(name, 1); // 'H' +getLetter(name, 0); // '' +getLetter(name, 6); // 't' +``` diff --git a/modules/45-logic/70-logical-expressions/ru/README.md b/modules/45-logic/70-logical-expressions/ru/README.md new file mode 100644 index 0000000..a0b1a1f --- /dev/null +++ b/modules/45-logic/70-logical-expressions/ru/README.md @@ -0,0 +1,131 @@ + +Посмотрите на код ниже и попробуйте угадать, что будет напечатано на экран? + +```javascript +console.log(0 || 1); +``` + +Правильный ответ: + +
+ 1 ++ +Оператор **ИЛИ** работает так, что его выполнение (слева направо) прерывается и возвращается результат первого аргумента, который можно преобразовать в `true`. + +Ниже пример с оператором **И**: + +```javascript +console.log(0 && 1); +``` + +
+ 0 ++ +Оператор **И** работает так, что его выполнение (слева направо) прерывается и возвращается результат первого аргумента, который можно преобразовать в `false`. + +В JavaScript есть два простых правила, по которым происходят преобразования: + +* `0`, `''`, `undefined`, `NaN`, `null` приводятся к `false`. Эти значения называют [falsy](https://developer.mozilla.org/ru/docs/Glossary/Falsy). +* Всё остальное приводится к `true` + +Этим активно пользуются в разработке, например, для определения значения по умолчанию: + +```javascript +const value = name || ''; +// Примеры +234 || ''; // 234 +'hexlet' || ''; // 'hexlet' +undefined || ''; // '' +``` + +https://replit.com/@hexlet/js-basics-logical-expressions + +Если `name` примет одно из falsy-значений, константе `value` будет присвоена пустая строка. В этом случае в последующем коде мы сможем работать с `value` как со строкой. + +Но здесь есть потенциальный баг. Если `name` содержит falsy-значение, а присваивание константе value значений типа `0`, `undefined`, `NaN` или `null` допустимо, то код выше начнет работать неверно: + +```javascript +// Упс +false || ''; // '' +0 || ''; // '' +undefined || ''; // '' +``` + +В одном из уроков мы рассмотрели операторы сравнения `===` и `!==` и упомянули, что в JavaScript так же есть операторы `==` и `!=`, но их не стоит использовать. Отличия как раз заключаются в преобразовании типов: + +```javascript +console.log('' === false); // => false +console.log('' == false); // => true +``` + +Пустая строка и `false` — это разные значения, поэтому оператор `===` говорит «ложь! они не равны!». + +Но оператор `==` преобразует типы, и с его точки зрения пустая строка и `false` равны. + +Это преобразование неявное, поэтому по возможности избегайте операторов `==` и `!=`. + +--- + +Вспомните операцию отрицания: + +```javascript +const answer = true; +console.log(!answer); // => false +``` + +Отрицание работает внутри выражений: + +```javascript +!false || ''; // true +``` + +Если выражение обернуть в скобки и поставить перед ними `!`, то будет отрицание всего выражения: + +```javascript +// Выражение обернуто в скобки +console.log(!('' === false)); // => true +console.log(!('' == false)); // => false +``` + +При двойном отрицании `!!` итоговое значение равно начальному: + +```javascript +const answer = true; +console.log(!!answer); // => true +``` + +Но здесь дополнительно может происходить преобразование типа. Поэтому результатом двойного отрицания всегда будет значение типа *boolean*. Этим приемом иногда пользуются, чтобы поменять тип данных. + +## Ошибка выбора + +Представьте себе задачу, в которой нам нужно проверить, что значение равно либо одному, либо другому. Например переменная `value` должна содержать одно из двух значений: `first` или `second`. Начинающие разработчики иногда записывают это выражение так: + +```javascript +value === ('first' || 'second') +``` + +В голове мы это себе примерно так и представляем, но языки работают по-другому, поэтому такой код приведет к неверному результату. Как его правильно прочитать? Мы должны вспомнить приоритет выполнения операций. Первым делом вычисляется все что указано в скобках, то есть `'first' || 'second'`. Если выполнить этот код в repl, то вывод будет таким: + +```bash +node +'Welcome to Node.js v17.4.0. +> 'first' || 'second' +'first' +> +``` + +Теперь мы можем заменить исходное выражение, на частично вычисленное: + +```javascript +value === 'first' +``` + +Совсем не то, что мы ожидали. А теперь вернемся к началу, и напишем проверку правильно: + +```javascript +// Скобки ставить не обязательно, +// потому что приоритет === выше чем приоритет || +value === 'first' || value === 'second' +``` diff --git a/modules/45-logic/70-logical-expressions/ru/data.yml b/modules/45-logic/70-logical-expressions/ru/data.yml new file mode 100644 index 0000000..358f2ec --- /dev/null +++ b/modules/45-logic/70-logical-expressions/ru/data.yml @@ -0,0 +1,7 @@ +name: Результат логических выражений +tips: + - | + [Boolean](https://ru.wikipedia.org/wiki/Логический_тип) + - > + [Извлечение символов из + строки](https://ru.code-basics.com/languages/javascript/lessons/symbols) diff --git a/modules/48-conditionals/30-if/ru/EXERCISE.md b/modules/48-conditionals/30-if/ru/EXERCISE.md new file mode 100644 index 0000000..cc8037e --- /dev/null +++ b/modules/48-conditionals/30-if/ru/EXERCISE.md @@ -0,0 +1,7 @@ + +Реализуйте функцию `guessNumber()`, которая принимает число и проверяет, равно ли число заданному (пусть это будет 42). Если равно, то функция должна вернуть строку `'You win!'`, в противном случае нужно вернуть строку `'Try again!'`. + +```javascript +guessNumber(42) // You win! +guessNumber(61) // Try again! +``` diff --git a/modules/48-conditionals/30-if/ru/README.md b/modules/48-conditionals/30-if/ru/README.md new file mode 100644 index 0000000..bac771e --- /dev/null +++ b/modules/48-conditionals/30-if/ru/README.md @@ -0,0 +1,43 @@ + +Условные конструкции позволяют изменить поведение программы в зависимости от проверяемых условий. Благодаря им у нас появляется возможность писать сложные программы, ведущие себя по разному, в зависимости от ситуации. + +Напишем, для примера, функцию, которая определяет тип переданного предложения. Для начала она будет отличать обычные предложения от вопросительных. + +```javascript +const getTypeOfSentence = (sentence) => { + const lastChar = sentence[sentence.length - 1]; + if (lastChar === '?') { + return 'question'; + } + + return 'general'; +}; + +getTypeOfSentence('Hodor'); // general +getTypeOfSentence('Hodor?'); // question +``` + +https://replit.com/@hexlet/js-basics-if + +`if` - конструкция языка, управляющая порядком выполнения инструкций. В скобках ей передается выражение-предикат, а затем описывается блок кода в фигурных скобках. Этот блок кода будет выполнен, только если предикат — истина. + +Если предикат — ложь, то блок кода в фигурных скобках пропускается, и функция продолжает свое выполнение дальше. В нашем случае следующая строчка кода — `return 'general';` — заставит функцию вернуть строку и завершиться. + +Как видите, `return` может находиться где угодно в функции. В том числе внутри блока кода с условием. + +Если в фигурных скобках после `if` содержится только одна строчка кода, то фигурные скобки можно не писать и сделать так: + +```javascript +const getTypeOfSentence = (sentence) => { + const lastChar = sentence[sentence.length - 1]; + if (lastChar === '?') + return 'question'; + + return 'general'; +}; + +console.log(getTypeOfSentence('Hodor')); // => general +console.log(getTypeOfSentence('Hodor?')); // => question +``` + +Советуем не делать так и **всегда писать фигурные скобки**. В таком случае явно видно, где начинается и заканчивается тело условия. Код становится более чётким и понятным. diff --git a/modules/48-conditionals/30-if/ru/data.yml b/modules/48-conditionals/30-if/ru/data.yml new file mode 100644 index 0000000..fd9d0e2 --- /dev/null +++ b/modules/48-conditionals/30-if/ru/data.yml @@ -0,0 +1,8 @@ +name: Условная конструкция (if) +tips: + - > + [if](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else) +definitions: + - name: Условные конструкции + description: | + изменяют поведение программы в зависимости от проверяемых условий diff --git a/modules/48-conditionals/40-if-else/ru/EXERCISE.md b/modules/48-conditionals/40-if-else/ru/EXERCISE.md new file mode 100644 index 0000000..b534df0 --- /dev/null +++ b/modules/48-conditionals/40-if-else/ru/EXERCISE.md @@ -0,0 +1,13 @@ + +Реализуйте функцию `normalizeUrl()`, которая выполняет так называемую нормализацию данных. Она принимает адрес сайта и возвращает его с *https://* в начале. + +Функция принимает адреса в виде *АДРЕС* или *https://АДРЕС*, но всегда возвращает адрес в виде *https://АДРЕС* + +Можно использовать метод [startsWith()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith), чтобы проверить, начинается ли строка с префикса *https://*. А потом на основе этого добавлять или не добавлять *https://*. + +Примеры вызова: + +```javascript +normalizeUrl("google.com"); // "https://google.com" +normalizeUrl("https://ai.fi"); // "https://ai.fi" +``` diff --git a/modules/48-conditionals/40-if-else/ru/README.md b/modules/48-conditionals/40-if-else/ru/README.md new file mode 100644 index 0000000..effa5f8 --- /dev/null +++ b/modules/48-conditionals/40-if-else/ru/README.md @@ -0,0 +1,54 @@ + +Напишем функцию `getTypeOfSentence()`, которая анализирует текст и возвращает описание его тона: для обычных предложений – *General sentence*, для вопросительных – *Question sentence*. + +```javascript + getTypeOfSentence('Hodor'); // General sentence + getTypeOfSentence('Hodor?'); // Question sentence +``` + +Реализация функции: + +```javascript +const getTypeOfSentence = (sentence) => { + // Объявляем переменную, в которую запишем тип предложения + let sentenceType; + // Предикат, проверяющий окончание текста + // Если он оканчивается на символ '?', то вернётся true, + // иначе false + if (sentence.endsWith('?')) { + // Если условие выше сработало, + // то это вопросительное предложение. + // Присваиваем sentenceType соответствующее значение. + sentenceType = 'Question'; + } else { + // Во всех остальных случаях предложение — обычное + sentenceType = 'General'; + } + + // С помощью интерполяции формируем строку + return `${sentenceType} sentence`; +}; +``` + +https://replit.com/@hexlet/js-basics-if-else + +Мы добавили ключевое слово `else` и новый блок с фигурными скобками. Этот блок выполнится, только если условие в `if` — ложь. + +Существует два способа оформления конструкции *if-else*. С помощью отрицания можно изменить порядок блоков: + +```javascript +const getTypeOfSentence = (sentence) => { + let sentenceType; + // Добавилось отрицание + // Содержимое else переехало в if и наоборот + if (!sentence.endsWith('?')) { + sentenceType = 'General'; + } else { + sentenceType = 'Question'; + } + + return `${sentenceType} sentence`; +}; +``` + +Какой способ предпочтительнее? Человеческому мозгу проще мыслить прямолинейно, а не через отрицание. Старайтесь выбирать проверку, которая не содержит отрицаний, и подстраивайте содержимое блоков под неё. diff --git a/modules/48-conditionals/40-if-else/ru/data.yml b/modules/48-conditionals/40-if-else/ru/data.yml new file mode 100644 index 0000000..5a3244e --- /dev/null +++ b/modules/48-conditionals/40-if-else/ru/data.yml @@ -0,0 +1,9 @@ +name: else +tips: + - > + [if...else](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else) +definitions: + - name: else + description: >- + способ задать блок кода, который будет выполнен, если условие с `if` не + удовлетворено diff --git a/modules/48-conditionals/50-else-if/ru/EXERCISE.md b/modules/48-conditionals/50-else-if/ru/EXERCISE.md new file mode 100644 index 0000000..be41fae --- /dev/null +++ b/modules/48-conditionals/50-else-if/ru/EXERCISE.md @@ -0,0 +1,19 @@ + +На электронной карте Вестероса, которую реализовал Сэм, союзники Старков отображены зеленым кружком, враги — красным, а нейтральные семьи — серым. + +Напишите для Сэма функцию `whoIsThisHouseToStarks()`, которая принимает на вход фамилию семьи и возвращает одно из трёх значений: `'friend'`, `'enemy'`, `'neutral'`. + +Правила определения: + +* Друзья (`'friend'`): 'Karstark', 'Tally' +* Враги (`'enemy'`): 'Lannister', 'Frey' +* Любые другие семьи считаются нейтральными + +Примеры вызова: + +```javascript +whoIsThisHouseToStarks('Karstark'); // friend +whoIsThisHouseToStarks('Frey'); // enemy +whoIsThisHouseToStarks('Joar'); // neutral +whoIsThisHouseToStarks('Ivanov'); // neutral +``` diff --git a/modules/48-conditionals/50-else-if/ru/README.md b/modules/48-conditionals/50-else-if/ru/README.md new file mode 100644 index 0000000..093ce65 --- /dev/null +++ b/modules/48-conditionals/50-else-if/ru/README.md @@ -0,0 +1,63 @@ + +Функция `getTypeOfSentence()` из предыдущего урока различает только вопросительные и обычные предложения. Давайте попробуем добавить поддержку восклицательных предложений: + +```javascript +const getTypeOfSentence = (sentence) => { + const lastChar = sentence[sentence.length - 1]; + let sentenceType; + + if (lastChar === '!') { + sentenceType = 'exclamation'; + } else { + sentenceType = 'normal'; + } + + if (lastChar === '?') { + sentenceType = 'question'; + } + + return `Sentence is ${sentenceType}`; +}; + +getTypeOfSentence('Who?'); // Sentence is question +getTypeOfSentence('No'); // Sentence is normal +getTypeOfSentence('No!'); // Sentence is exclamation +``` + +https://replit.com/@hexlet/js-basics-conditionals + +Мы добавили ещё одну проверку ("exclamation" переводится «восклицание»). Технически функция работает, но с точки зрения семантики есть проблемы. + +- Проверка на наличие вопросительного знака происходит в любом случае, даже если уже был обнаружен восклицательный знак. +- Ветка `else` описана именно для первого условия, но не для второго. + +Правильнее будет воспользоваться ещё одной возможностью условной конструкции: + +```javascript +const getTypeOfSentence = (sentence) => { + const lastChar = sentence[sentence.length - 1]; + let sentenceType; + + if (lastChar === '?') { + sentenceType = 'question'; + } else if (lastChar === '!') { + sentenceType = 'exclamation'; + } else { + sentenceType = 'normal'; + } + + return `Sentence is ${sentenceType}`; +}; + +getTypeOfSentence('Who?'); // Sentence is question +getTypeOfSentence('No'); // Sentence is normal +getTypeOfSentence('No!'); // Sentence is exclamation +``` + +Теперь все условия выстроены в единую конструкцию. `else if` — это «если не выполнено предыдущее условие, но выполнено текущее». Получается такая схема: + +- если последний символ это `?`, то `'question'` +- иначе, если последний символ это `!`, то `'exclamation'` +- иначе `'normal'` + +Выполнится только один из блоков кода, относящихся ко всей конструкции `if`. diff --git a/modules/48-conditionals/50-else-if/ru/data.yml b/modules/48-conditionals/50-else-if/ru/data.yml new file mode 100644 index 0000000..2d46cb3 --- /dev/null +++ b/modules/48-conditionals/50-else-if/ru/data.yml @@ -0,0 +1,8 @@ +name: Конструкция else if +tips: + - > + [else + if](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else#using_else_if) +definitions: + - name: else if + description: способ задать несколько альтернативных условий. diff --git a/modules/48-conditionals/60-ternary-operator/ru/EXERCISE.md b/modules/48-conditionals/60-ternary-operator/ru/EXERCISE.md new file mode 100644 index 0000000..41f1a95 --- /dev/null +++ b/modules/48-conditionals/60-ternary-operator/ru/EXERCISE.md @@ -0,0 +1,27 @@ + +Реализуйте функцию `convertText()`, которая принимает на вход строку и, если первая буква не заглавная, возвращает перевернутый вариант исходной строки. Если первая буква заглавная, то строка возвращается без изменений. Если на вход передана пустая строка, функция должна вернуть пустую строку. + +Примеры вызова: + +```javascript +convertText('Hello'); // Hello +convertText('hello'); // olleh + +// Не забудьте учесть пустую строку +convertText(''); // '' +``` + +Перевернуть строчку можно используя функцию `reverse()`. В качестве аргумента в неё нужно передать строку, которую мы хотим перевернуть: + +```javascript +const result = reverse('Hello!'); +console.log(result); // => !olleH +``` + +Есть разные подходы к решению этой задачи. Возможно, вам пригодится метод [toUpperCase()](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase) и возможность получения символа из строки (например, `str[0]`). + +Попробуйте написать два варианта функции: с обычным if-else, и с тернарным оператором. + +## Подсказки + +* Подумайте какую проверку нужно написать первым делом: проверку заглавности буквы или является ли пустой строка. Что первичнее? diff --git a/modules/48-conditionals/60-ternary-operator/ru/README.md b/modules/48-conditionals/60-ternary-operator/ru/README.md new file mode 100644 index 0000000..b9e518a --- /dev/null +++ b/modules/48-conditionals/60-ternary-operator/ru/README.md @@ -0,0 +1,72 @@ + +Посмотрите на определение функции, которая возвращает модуль переданного числа: + +```javascript +const abs = (number) => { + if (number >= 0) { + return number; + } + + return -number; +}; + +abs(10); // 10 +abs(-10); // 10 +``` + +Можно ли записать её лаконичнее? Что-то вроде `return <ответ в зависимости от условия>`? Для этого справа от return должно быть выражение, но `if` — это инструкция, а не выражение. + +В JavaScript существует конструкция, которая по своему действию аналогична конструкции *if-else*, но при этом является выражением. Она называется **тернарный оператор**. + +Тернарный оператор — единственный в своем роде оператор, требующий три операнда: + +```javascript +const abs = (number) => { + return number >= 0 ? number : -number; +}; +``` + +Общий паттерн выглядит так: `
4diff --git a/modules/50-loops/10-while/ru/README.md b/modules/50-loops/10-while/ru/README.md new file mode 100644 index 0000000..3b3467a --- /dev/null +++ b/modules/50-loops/10-while/ru/README.md @@ -0,0 +1,105 @@ + +Программы, которые мы пишем, становятся всё сложнее и объемнее. Они все ещё очень далеки от реальных программ, где количество строк кода измеряется десятками и сотнями тысяч (а иногда и миллионами), но текущая сложность уже способна заставить напрячься людей без опыта. Начиная с этого урока, мы переходим к одной из самых сложных базовых тем в программировании – циклам. + +Любые прикладные программы служат очень прагматичным целям. Они помогают управлять сотрудниками, финансами, развлекают в конце концов. Несмотря на различия, все эти программы выполняют заложенные в них алгоритмы, которые очень похожи между собой. Что это такое? Алгоритм — это последовательность действий (инструкций), которая приводит нас к некоему ожидаемому результату. В принципе, это описание подходит под любую программу, но под алгоритмами обычно понимается что-то более специфичное. + +Представьте себе, что у нас есть книга и мы хотим найти внутри неё какую-то конкретную фразу. Саму фразу мы помним, но не знаем, на какой она странице. Как найти нужную страницу? Самый простой (и долгий) способ — последовательно просматривать страницы до тех пор, пока мы не найдем нужную. В худшем случае придется просмотреть все страницы, но результат мы всё равно получим. Именно этот процесс и называется алгоритмом. Он включает в себя логические проверки (нашли ли фразу) и перебор страниц. Количество страниц, которое придется посмотреть, заранее неизвестно, но сам процесс просмотра повторяется из раза в раз совершенно одинаковым образом. Для выполнения повторяющихся действий как раз и нужны циклы. Каждый повтор, в таком случае, называется итерацией. + +Допустим мы хотим написать функцию, которая выводит на экран все числа от 1 до указанного (через аргументы): + +```javascript +printNumbers(3); +// => 1 +// => 2 +// => 3 +``` + +Эту функцию невозможно реализовать уже изученными средствами, так как количество выводов на экран заранее неизвестно. А с циклами это не составит никаких проблем: + +```javascript +const printNumbers = (lastNumber) => { + // i сокращение от index (порядковый номер) + // используется по общему соглашению во множестве языков + // как счетчик цикла + let i = 1; + + while (i <= lastNumber) { + console.log(i); + i = i + 1; + } + console.log('finished!'); +}; + +printNumbers(3); +``` + +
3
2
1
finished!
+1 +2 +3 +finished! ++ +https://replit.com/@hexlet/js-basics-while + +В коде функции использован цикл `while`. Он состоит из трёх элементов: + +* Ключевое слово `while`. Несмотря на схожесть с вызовом функций, это не вызов функции. +* Предикат. Условие, которое указывается в скобках после `while`. Это условие вычисляется и проверяется перед выполнением тела цикла на каждой итерации. +* Тело цикла. Блок кода в фигурных скобках. Этот блок аналогичен блоку кода в функциях. Всё, что определено внутри этого блока (константы или переменные), видно только внутри этого блока. + +Конструкция читается так: «пока истинно условие (предикат) `i <= lastNumber` делать то, что указано в теле цикла». Разберём работу этого кода для вызова `printNumbers(3)`: + +```javascript +// Инициализируется i +let i = 1; + +// Предикат возвращает true, поэтому выполняется тело цикла +while (1 <= 3) +// console.log(1); +// i = 1 + 1; + +// Закончилось тело цикла, поэтому происходит возврат в начало +while (2 <= 3) +// console.log(2); +// i = 2 + 1; + +// Закончилось тело цикла, поэтому происходит возврат в начало +while (3 <= 3) +// console.log(3); +// i = 3 + 1; + +// Предикат возвращает false, поэтому выполнение переходит за цикл +while (4 <= 3) + +// console.log('finished!'); +// На этом этапе i равен 4, но он нам уже не нужен +// функция завершается +``` + +Самое главное в цикле — завершение его работы (выход из цикла). Процесс, который порождает цикл, должен в конце концов остановиться. Ответственность за остановку полностью лежит на программисте. Обычно задача сводится к введению переменной, называемой «счётчиком цикла». Сначала счётчик инициализируется, то есть ему задаётся начальное значение. В нашем примере это инструкция `let i = 1`, выполняемая до входа в цикл. Затем в условии цикла проверяется, достиг ли счётчик своего предельного значения. И, наконец, счётчик меняет свое значение `i = i + 1`. + +На этом моменте новички делают больше всего ошибок. Например, случайно забытое увеличение счётчика или неправильная проверка в предикате способны привести к зацикливанию. Это ситуация, при которой цикл работает бесконечно и программа никогда не останавливается. В таком случае приходится её завершать принудительно (кто знает, может быть когда зависают реальные программы, в этот момент внутри них выполняется бесконечный цикл). + +```javascript +const printNumbers = (lastNumber) => { + let i = 1; + + // Этот цикл никогда не остановится + // и будет печатать всегда одно значение + while (i <= lastNumber) { + console.log(i); + } + console.log('finished!'); +}; +``` + +В некоторых случаях бесконечные циклы полезны. Здесь мы такие случаи не рассматриваем, но полезно видеть как выглядит этот код: + +```javascript +while (true) { + // Что-то делаем +} +``` + +Подводя итог. Когда всё же нужны циклы, а когда можно обойтись без них? Физически невозможно обойтись без циклов тогда, когда алгоритм решения задачи требует повторения каких-то действий, как в примере с книгой, и количество этих операций заранее неизвестно. diff --git a/modules/50-loops/10-while/ru/data.yml b/modules/50-loops/10-while/ru/data.yml new file mode 100644 index 0000000..6465a68 --- /dev/null +++ b/modules/50-loops/10-while/ru/data.yml @@ -0,0 +1,8 @@ +name: Цикл While +tips: + - > + [Цикл + while](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/while) +definitions: + - name: Цикл While + description: инструкция для повторения кода, пока удовлетворяется какое-то условие. diff --git a/modules/50-loops/20-aggregation-numbers/ru/EXERCISE.md b/modules/50-loops/20-aggregation-numbers/ru/EXERCISE.md new file mode 100644 index 0000000..059b2de --- /dev/null +++ b/modules/50-loops/20-aggregation-numbers/ru/EXERCISE.md @@ -0,0 +1,8 @@ + +Реализуйте функцию `multiplyNumbersFromRange()`, которая перемножает числа в указанном диапазоне включая границы диапазона. Пример вызова: + +```javascript +multiplyNumbersFromRange(1, 5); // 1 * 2 * 3 * 4 * 5 = 120 +multiplyNumbersFromRange(2, 3); // 2 * 3 = 6 +multiplyNumbersFromRange(6, 6); // 6 +``` diff --git a/modules/50-loops/20-aggregation-numbers/ru/README.md b/modules/50-loops/20-aggregation-numbers/ru/README.md new file mode 100644 index 0000000..0b62e97 --- /dev/null +++ b/modules/50-loops/20-aggregation-numbers/ru/README.md @@ -0,0 +1,82 @@ + +Отдельный класс задач, который не может обойтись без циклов, называется агрегированием данных. К таким задачам относятся поиск максимального, минимального, суммы, среднего арифметического и т.п. Их главная особенность в том, что результат зависит от всего набора данных. Для расчета суммы нужно сложить **все** числа, для вычисления максимального нужно сравнить **все** числа. + +С такими задачами хорошо знакомы все, кто занимаются c числами, например бухгалтеры или маркетологи. Обычно их выполняют в таблицах наподобие Microsoft Excel или Google Tables. + +Разберем самый простой пример – поиск суммы набора чисел. Реализуем функцию, которая складывает числа в указанном диапазоне, включая границы. Диапазоном в данном случае называется ряд чисел от какого-то начала до определенного конца. Например, диапазон [1, 10] включает в себя все целые числа от 1 до 10. + +```javascript +sumNumbersFromRange(5, 7); // 5 + 6 + 7 = 18 +sumNumbersFromRange(1, 2); // 1 + 2 = 3 + +// [1, 1] диапазон с одинаковым началом и концом – тоже диапазон +// он в себя включает ровно одно число – саму границу диапазона +sumNumbersFromRange(1, 1); // 1 +sumNumbersFromRange(100, 100); // 100 +``` + +Для реализации этого кода нам понадобится цикл, так как сложение чисел – это итеративный процесс (он повторяется для каждого числа), а количество итераций зависит от размера диапазона. Перед тем, как смотреть код, попробуйте ответьте на вопросы ниже: + +* Каким значением инициализировать счетчик? +* Как он будет изменяться? +* Когда цикл должен остановиться? + +Попробуйте сначала подумать над этими вопросами, а затем посмотрите код ниже: + +```javascript +const sumNumbersFromRange = (start, finish) => { + // Технически можно менять start + // Но входные аргументы нужно оставлять в исходном значении + // Это сделает код проще для анализа + let i = start; + let sum = 0; // Инициализация суммы + + while (i <= finish) { // Двигаемся до конца диапазона + sum = sum + i; // Считаем сумму для каждого числа + i = i + 1; // Переходим к следующему числу в диапазоне + } + + // Возвращаем получившийся результат + return sum; +}; +``` + +https://replit.com/@hexlet/js-basics-aggregation-numbers + +Общая структура цикла здесь стандартна. Есть счетчик, который инициализируется начальным значением диапазона, есть сам цикл с условием остановки при достижении конца диапазона, и, наконец, изменение счетчика в конце тела цикла. Количество итераций в таком цикле равно `finish - start + 1`. То есть для диапазона от 5 до 7 – это 7 - 5 + 1, то есть 3 итерации. + +Главные отличия от обычной обработки связаны с логикой вычислений результата. В задачах на агрегацию всегда есть какая-то переменная, которая хранит внутри себя результат работы цикла. В коде выше это `sum`. На каждой итерации цикла происходит её изменение, прибавление следующего числа в диапазоне: `sum = sum + i`. Весь процесс выглядит так: + +```javascript +// Для вызова sumNumbersFromRange(2, 5); +let sum = 0; +sum = sum + 2; // 2 +sum = sum + 3; // 5 +sum = sum + 4; // 9 +sum = sum + 5; // 14 +// 14 – результат сложения чисел в диапазоне [2, 5] +``` + +У переменной `sum` есть начальное значение, равное 0. Зачем вообще задавать значение? Любая повторяющаяся операция начинается с какого-то значения. Нельзя просто так объявить переменную и начать с ней работать внутри цикла. Это приведет к неверному результату: + +```javascript +// начальное значение не задано +// js автоматически делает его равным undefined +let sum; + +// первая итерация цикла +sum = sum + 2; // ? +``` + +В результате такого вызова внутри `sum` окажется `NaN`, то есть не-число. Оно возникает из-за попытки сложить `2` и `undefined`. Значит какое-то значение всё же нужно. Почему в коде выше выбран 0? Очень легко проверить, что все остальные варианты приведут к неверному результату. Если начальное значение будет равно 1, то результат получится на 1 больше, чем нужно. + +В математике существует понятие **нейтральный элемент операции** (у каждой операции свой элемент). Это понятие имеет очень простой смысл. Операция с этим элементом не изменяет то значение, над которым проводится операция. В сложении любое число плюс ноль дает само число. При вычитании – тоже самое. Даже у конкатенации есть нейтральный элемент – это пустая строка: `'' + 'one'` будет 'one'. + +Вопрос на самопроверку. Какой нейтральный элемент у операции умножения? Для ответа на этот вопрос, найдите число, которое не меняет любые другие числа при умножения на него. + +