From ac01740eb6450d5924ec98337a314700c0560ebc Mon Sep 17 00:00:00 2001 From: Nikolay Gagarinov Date: Fri, 29 May 2026 20:46:08 +0500 Subject: [PATCH] feat(45-logic): port theory from Python, add string-comparison lesson MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 10-bool-type: расширена теория (операции сравнения, ===/!==, предикаты isInfant/isNegative); - 28-logical-negation: добавлены комбинирование с &&/||, приоритет, скобки, пример canDrive, законы де Моргана (not→!, and→&&, or→||); - НОВЫЙ урок 17-bool-strings («Сравнение строк», из Python 45/15): лексикографическое сравнение, charCodeAt вместо ord, предикаты строк startsWith/endsWith/includes; JS-урок «Предикаты» (15) сохранён. Новый урок пока только в RU-локали (en/es — на этапе перевода, как и остальные уроки). Co-Authored-By: Claude Opus 4.8 (1M context) --- modules/45-logic/10-bool-type/ru/README.md | 61 ++++++++++++----- modules/45-logic/17-bool-strings/Makefile | 2 + modules/45-logic/17-bool-strings/index.js | 5 ++ .../45-logic/17-bool-strings/ru/EXERCISE.md | 8 +++ modules/45-logic/17-bool-strings/ru/README.md | 53 +++++++++++++++ modules/45-logic/17-bool-strings/ru/data.yml | 11 ++++ modules/45-logic/17-bool-strings/test.js | 10 +++ .../45-logic/28-logical-negation/ru/README.md | 65 +++++++++++++++++-- 8 files changed, 194 insertions(+), 21 deletions(-) create mode 100644 modules/45-logic/17-bool-strings/Makefile create mode 100644 modules/45-logic/17-bool-strings/index.js create mode 100644 modules/45-logic/17-bool-strings/ru/EXERCISE.md create mode 100644 modules/45-logic/17-bool-strings/ru/README.md create mode 100644 modules/45-logic/17-bool-strings/ru/data.yml create mode 100644 modules/45-logic/17-bool-strings/test.js diff --git a/modules/45-logic/10-bool-type/ru/README.md b/modules/45-logic/10-bool-type/ru/README.md index 3e458314..2c1b2b5e 100644 --- a/modules/45-logic/10-bool-type/ru/README.md +++ b/modules/45-logic/10-bool-type/ru/README.md @@ -1,34 +1,63 @@ -В JavaScript есть специальный тип данных — **boolean** (булев тип). Он содержит только два значения: `true` (истина) и `false` (ложь). +Кроме арифметических операций, в математике есть операции сравнения, например `5 > 4` или `3 < 1`. Они есть и в программировании. Сравнения часто применяются в реальных задачах. Например, когда мы оформляем покупку в интернет-магазине, система проверяет, хватает ли у пользователя денег на счёте: если сумма на счёте больше или равна цене товара, заказ подтверждается, иначе появляется сообщение о нехватке средств. -## Операторы сравнения +## Сравнение в программировании -Операторы сравнения возвращают булево значение: +Начнём с примера, в котором сравниваются два числа: ```javascript -console.log(5 > 3); // => true -console.log(5 < 3); // => false -console.log(5 === 5); // => true -console.log(5 !== 3); // => true +console.log(5 > 4); // => true +console.log(4 > 4); // => false ``` +Результатом сравнения является значение типа **boolean** (булев тип). У него всего два возможных значения: `true` (истина) и `false` (ложь). Это специальные значения языка, их можно использовать напрямую: + +```javascript +console.log(true); +console.log(false); +``` + +На практике так их используют редко, но на их основе строится вся логика поведения программы. Мы сталкиваемся с этим каждый день: вводим пин-коды и пароли, выполняем действия, результат которых может быть разным. Программа рассуждает примерно так: *если так — делай раз, если иначе — делай два*. + +В JavaScript доступны следующие операции сравнения: + | Оператор | Смысл | |----------|-------| -| `>` | больше | | `<` | меньше | -| `>=` | больше или равно | | `<=` | меньше или равно | +| `>` | больше | +| `>=` | больше или равно | | `===` | строго равно | | `!==` | строго не равно | -## Функции, возвращающие boolean +Языки программирования переняли математические операции сравнения почти без изменений, кроме равенства и неравенства. В математике используется обычное `=`, но в программировании символ `=` уже занят — он присваивает переменным значения. Поэтому для сравнения на равенство в JavaScript используют `===`, а на неравенство — `!==` (тройной и с восклицательным знаком — это «строгое» сравнение, к которому мы ещё вернёмся). + +```javascript +console.log(5 >= 3); // => true +console.log(7 < 0); // => false +console.log(5 > 5); // => false +console.log(5 >= 5); // => true +console.log(2 === 5); // => false +console.log(2 !== 5); // => true +``` + +Когда в сравнении используют конкретные значения, операция кажется бессмысленной: результат и так известен и всегда одинаков. Но всё меняется, когда значения могут быть разными. Напишем простую функцию, которая принимает возраст ребёнка и определяет, младенец ли он. Младенцами считаются дети до двух лет (два не включается): + +```javascript +const isInfant = (age) => age < 2; + +console.log(isInfant(3)); // => false +console.log(isInfant(2)); // => false +console.log(isInfant(1)); // => true +console.log(isInfant(0)); // => true +``` + +## Предикаты -Функции, возвращающие `true` или `false`, называют **предикатами**. По соглашению их называют с приставкой `is`, `has`, `can`: +Когда функции возвращают результат сравнения, они обычно отвечают на вопрос «да» или «нет». Такие функции называют **предикатами**. Их легко узнать: они возвращают логическое значение `true` или `false`, а в их названии часто есть проверяемое утверждение (`is`, `has`, `can`). Вот функция, проверяющая, является ли число отрицательным: ```javascript -function isPensioner(age) { - return age >= 60; -} +const isNegative = (number) => number < 0; -console.log(isPensioner(65)); // => true -console.log(isPensioner(30)); // => false +console.log(isNegative(-5)); // => true +console.log(isNegative(7)); // => false ``` diff --git a/modules/45-logic/17-bool-strings/Makefile b/modules/45-logic/17-bool-strings/Makefile new file mode 100644 index 00000000..d0d0a48c --- /dev/null +++ b/modules/45-logic/17-bool-strings/Makefile @@ -0,0 +1,2 @@ +test: + @ test.sh diff --git a/modules/45-logic/17-bool-strings/index.js b/modules/45-logic/17-bool-strings/index.js new file mode 100644 index 00000000..68cb82fa --- /dev/null +++ b/modules/45-logic/17-bool-strings/index.js @@ -0,0 +1,5 @@ +// BEGIN +const isLongWord = (word) => word.length > 5; +// END + +export default isLongWord; diff --git a/modules/45-logic/17-bool-strings/ru/EXERCISE.md b/modules/45-logic/17-bool-strings/ru/EXERCISE.md new file mode 100644 index 00000000..747d05cf --- /dev/null +++ b/modules/45-logic/17-bool-strings/ru/EXERCISE.md @@ -0,0 +1,8 @@ +При регистрации на сайте программа проверяет, что пароль достаточно длинный — больше 5 символов. Напишите функцию `isLongWord()`, которая возвращает `true`, если длина переданного слова больше 5 символов, и `false` в противном случае. + +Пример работы: + +```javascript +isLongWord('apple'); // => false +isLongWord('banana'); // => true +``` diff --git a/modules/45-logic/17-bool-strings/ru/README.md b/modules/45-logic/17-bool-strings/ru/README.md new file mode 100644 index 00000000..bc65903d --- /dev/null +++ b/modules/45-logic/17-bool-strings/ru/README.md @@ -0,0 +1,53 @@ +Операции сравнения работают не только с числами, но и со строками. В JavaScript строки сравниваются лексикографически: посимвольно слева направо по числовым кодам символов (Unicode). + +```javascript +console.log('apple' < 'banana'); // => true +console.log('cat' > 'dog'); // => false +console.log('abc' === 'abc'); // => true +console.log('hello' !== 'world'); // => true +``` + +Здесь `'apple' < 'banana'`, потому что код символа `a` (97) меньше кода `b` (98), и именно первый различающийся символ решает исход сравнения. Узнать код символа можно методом `charCodeAt()`: + +```javascript +console.log('a'.charCodeAt(0)); // => 97 +console.log('b'.charCodeAt(0)); // => 98 +``` + +Сравнение чувствительно к регистру: код `'Z'` (90) меньше кода `'a'` (97). Несколько примеров, где первые буквы в разном регистре: + +```javascript +console.log('Zebra' < 'apple'); // => true — 'Z'(90) < 'a'(97) +console.log('apple' < 'Banana'); // => false — 'a'(97) > 'B'(66) +console.log('Apple' < 'apple'); // => true — 'A'(65) < 'a'(97) +``` + +Напишем функцию, которая проверяет, начинается ли слово с заданной буквы. Для этого возьмём первый символ строки и сравним его с нужной буквой: + +```javascript +const startsWithLetter = (word, letter) => word[0] === letter; + +console.log(startsWithLetter('apple', 'a')); // => true +console.log(startsWithLetter('banana', 'a')); // => false +``` + +Операции сравнения — такие же выражения, как и арифметические. В них можно подставлять готовые значения и другие выражения, например `word[0]` выше. Можно использовать и свойство `.length`: + +```javascript +console.log('apple'.length > 3); // => true, потому что длина равна 5 +console.log('hi'.length > 3); // => false, потому что длина равна 2 +``` + +Сначала вычисляется `'apple'.length` (получается число `5`), а потом это число сравнивается с `3`. То есть сначала считаются операнды выражения, а затем выполняется сравнение. + +## Полезные предикаты + +У строк в JavaScript есть встроенные методы-предикаты. Они возвращают `true` или `false` и помогают проверять разные свойства строки: + +```javascript +console.log('hello'.startsWith('he')); // => true — строка начинается с 'he' +console.log('hello'.endsWith('lo')); // => true — строка заканчивается на 'lo' +console.log('hello'.includes('ell')); // => true — строка содержит 'ell' +``` + +Такие методы позволяют проверять строки на нужные условия прямо в коде, без написания дополнительных функций. diff --git a/modules/45-logic/17-bool-strings/ru/data.yml b/modules/45-logic/17-bool-strings/ru/data.yml new file mode 100644 index 00000000..730ee318 --- /dev/null +++ b/modules/45-logic/17-bool-strings/ru/data.yml @@ -0,0 +1,11 @@ +--- +name: Сравнение строк +tips: + - > + [Сравнение строк в + JavaScript](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Less_than) +definitions: + - name: Лексикографическое сравнение + description: >- + сравнение строк посимвольно слева направо по числовым кодам символов + (Unicode). diff --git a/modules/45-logic/17-bool-strings/test.js b/modules/45-logic/17-bool-strings/test.js new file mode 100644 index 00000000..648a30a0 --- /dev/null +++ b/modules/45-logic/17-bool-strings/test.js @@ -0,0 +1,10 @@ +// @ts-check + +import { expect, test } from 'vitest'; +import f from './index.js'; + +test('test', () => { + expect(f('apple')).toBe(false); + expect(f('banana')).toBe(true); + expect(f('pineapple')).toBe(true); +}); diff --git a/modules/45-logic/28-logical-negation/ru/README.md b/modules/45-logic/28-logical-negation/ru/README.md index 5b9dc262..5c8c56f6 100644 --- a/modules/45-logic/28-logical-negation/ru/README.md +++ b/modules/45-logic/28-logical-negation/ru/README.md @@ -1,7 +1,11 @@ +Наряду с логическими операторами **И** (`&&`) и **ИЛИ** (`||`), часто используется операция «**отрицание**». Она меняет логическое значение на противоположное. В JavaScript отрицанию соответствует унарный оператор `!`: -Наряду с конъюнкцией (И) и дизъюнкцией (ИЛИ), часто используется операция «отрицание». Отрицание меняет логическое значение на противоположное. В программировании ему соответствует унарный оператор `!`. +```javascript +!true; // false +!false; // true +``` -Если есть функция, проверяющая чётность числа, то с помощью отрицания можно выполнить проверку нечётности: +Например, если есть функция, проверяющая чётность числа, то с помощью отрицания можно выполнить проверку нечётности: ```javascript const isEven = (number) => number % 2 === 0; @@ -10,14 +14,65 @@ isEven(10); // true !isEven(10); // false ``` -То есть мы просто добавили `!` слева от вызова функции и получили обратное действие. +Мы просто добавили `!` слева от вызова функции и получили обратное действие. Отрицание позволяет выражать задуманные правила в коде без написания новых функций. -Отрицание — мощный инструмент, который позволяет лаконично выражать задуманные правила в коде без необходимости писать новые функции. +## Двойное отрицание -А что если написать так `!!isEven(10)`? Внезапно, но код сработает. В логике двойное отрицание подобно отсутствию отрицания вообще. +А что, если написать `!!isEven(10)`? Внезапно, но код сработает. В логике двойное отрицание равносильно отсутствию отрицания: ```javascript isEven(10); // true !isEven(10); // false !!isEven(10); // true ``` + +## Комбинирование с && и || + +`!` можно комбинировать с `&&` и `||`. Среди логических операторов у отрицания наивысший приоритет, поэтому оно применяется первым: + +```javascript +!true || true; // (!true) || true => false || true => true +!true && false; // (!true) && false => false && false => false +``` + +Скобки меняют порядок вычисления: + +```javascript +!(true || true); // !true => false +!(true && false); // !false => true +``` + +Практический пример — функция проверяет, может ли водитель сесть за руль: нужны права и трезвость: + +```javascript +const canDrive = (hasLicense, isDrunk) => hasLicense && !isDrunk; + +console.log(canDrive(true, false)); // => true (есть права, трезвый) +console.log(canDrive(true, true)); // => false (есть права, но пьяный) +console.log(canDrive(false, false)); // => false (нет прав) +``` + +## Законы де Моргана + +При работе со сложными логическими выражениями бывает нужно инвертировать их или переписать в эквивалентную, более читаемую форму. Для этого существуют **законы де Моргана** — два правила, описывающих, как отрицание распределяется по составному выражению: + +```javascript +!(a && b) === !a || !b +!(a || b) === !a && !b +``` + +Первый закон: отрицание конъюнкции равно дизъюнкции отрицаний. Проверим: + +```javascript +!(true && false); // !false => true +!true || !false; // false || true => true +``` + +Второй закон: отрицание дизъюнкции равно конъюнкции отрицаний: + +```javascript +!(true || false); // !true => false +!true && !false; // false && true => false +``` + +На практике законы де Моргана помогают упрощать условия. Например, вместо `!(isAdmin || isModerator)` можно написать `!isAdmin && !isModerator` — читается как «не администратор и не модератор».