Функции, условия и циклы
Теперь научимся программировать: принимать решения, повторять действия и собирать логику в функции.
Условия: if / else
Программа принимает решения по условию:
const age = 17;
if (age >= 18) {
console.log("Добро пожаловать!");
} else if (age >= 14) {
console.log("Нужно разрешение родителей");
} else {
console.log("Страница доступна взрослым");
}
=== строгое равенство, !==, >, <, >=, <=. Логические связки — && (и), || (или), ! (не).Тернарный оператор
Короткая запись «если — иначе» за одну строку:
const time = 20;
const greeting = time < 12 ? "Доброе утро" : "Добрый день/вечер";
Циклы
Циклы повторяют код. Считаем от 1 до 5:
for (let i = 1; i <= 5; i++) {
console.log("Раз " + i);
}
let n = 0;
while (n < 3) {
console.log("привет");
n++;
}
Чаще всего цикл нужен, чтобы перебрать массив:
const langs = ["HTML", "CSS", "JS"];
for (const lang of langs) {
console.log("Изучаю: " + lang);
}
for (let i = 0; i < langs.length; i++) {
console.log(i + ": " + langs[i]); // с индексами
}
Функции
Функция — именованный блок кода, который можно вызывать сколько угодно раз.
function add(a, b) {
return a + b;
}
const sum = add(2, 3); // 5
const multiply = (a, b) => a * b; // стрелочная функция
multiply(4, 5); // 20
() => {} — современный стиль короче: без function и return, если тело в одну строку.Методы массивов вместо циклов
Современный код часто использует встроенные методы:
const nums = [1, 2, 3, 4];
const doubled = nums.map(n => n * 2); // [2,4,6,8]
const even = nums.filter(n => n % 2 === 0); // [2,4]
const total = nums.reduce((acc, n) => acc + n, 0); // 10
Живой пример: цикл + условие
Классика: вывести числа от 1 до 15, где кратные 3 — как «Fizz», кратные 5 — как «Buzz»:
switch — выбор из многих вариантов
Когда веток больше двух-трёх и они сравнивают по одному значению, switch читается лучше цепочки if:
const role = "admin";
switch (role) {
case "admin":
console.log("Полный доступ");
break;
case "moderator":
console.log("Права модератора");
break;
default:
console.log("Гость");
}
break выполнение «провалится» в следующий case — это популярный источник скрытых багов.Логические операторы и короткое замыкание
&& и || возвращают не только true/false, а само значение — если результат уже ясен, остальное не вычисляется:
const user = { name: "Аня" };
const name = user.name || "Гость"; // если пусто — подставится "Гость"
const isAdmin = true;
isAdmin && console.log("Кнопка «Удалить» показана"); // выполнится только если true
console.log("" || "текст"); // "текст"
console.log(0 && "никогда"); // 0 (0 — «ложное» значение)
false, 0, "", null, undefined, NaN. Всё остальное — «истинное», включая пустые массивы и объекты.break и continue в циклах
Цикл можно досрочно остановить или пропустить итерацию:
for (let i = 1; i <= 6; i++) {
if (i === 3) continue; // пропустить тройку, цикл идёт дальше
if (i === 5) break; // остановиться на пятёрке
console.log(i); // 1, 2, 4
}
continue — «следующая итерация», break — «хватит». break работает и в switch.Область видимости переменных
let и const живут только внутри своего блока { ... }, а var «вылезает» за его пределы — отсюда баги:
if (true) {
let a = 1; // только внутри условия
var b = 2; // утечёт наружу!
}
console.log(a); // ReferenceError: a is not defined
console.log(b); // 2 — работает, но почему? var не знает блока
var не используют: его «весёлая» область видимости порождает труднонаходимые ошибки. Современный код — только const/let.Объект Math
Стандартный набор математических функций — без подключения библиотек:
Math.round(4.6); // 5 — округление
Math.floor(4.9); // 4 — вниз
Math.ceil(4.1); // 5 — вверх
Math.random(); // число от 0 до 1
Math.max(1, 9, 4); // 9
Math.min(1, 9, 4); // 1
const dice = Math.floor(Math.random() * 6) + 1; // кубик от 1 до 6
A + Math.floor(Math.random() * (B - A + 1)). Выигрывает в лотереях казино и играх на сайтах.Цикл по объекту: for...in и Object.keys
Объекты перебираются иначе, чем массивы. for...in идёт по ключам, а утилиты Object.* отдают ключи, значения или пары массивом:
const config = { theme: "dark", lang: "ru" };
for (const key in config) {
console.log(key, config[key]); // theme dark, lang ru
}
Object.keys(config); // ["theme", "lang"]
Object.values(config); // ["dark", "ru"]
Object.entries(config); // [["theme","dark"],["lang","ru"]]
Object.entries + destructuring — самый элегантный перебор: for (const [key, value] of Object.entries(config)).Параметры по умолчанию и rest
Функции могут подставлять значения, если аргумент не передан, и «собирать» все лишние аргументы в массив:
function greet(name = "Гость") {
return `Привет, ${name}!`;
}
greet(); // "Привет, Гость!"
function sumAll(...nums) { // rest-параметр
return nums.reduce((acc, n) => acc + n, 0);
}
sumAll(1, 2, 3, 4); // 10
const nums = [1, 2, 3];
Math.max(...nums); // 3 — распаковка массива в аргументы
... перед параметром функции — «rest» (собрать), перед массивом в вызове — «spread» (распаковать).Ранний выход (early return)
Стиль «охрана у входа» ускоряет чтение кода: редкие случаи проверяем в начале и выходим, основную логику оставляем без каскада вложенных if:
function moveUser(user, where) {
if (!user) return; // нет пользователя — дальше не идём
if (!where) return "Куда едем?";
// основная логика без лишней вложенности
return `Перемещаем ${user.name} в ${where}`;
}
Замыкания: функция внутри функции
Функция видит переменные, объявленные вокруг неё, даже после выхода из внешней функции. Так рождается «счётчик с памятью»:
function makeCounter() {
let count = 0;
return function() {
count++;
return count;
};
}
const counter = makeCounter();
counter(); // 1
counter(); // 2
counter(); // 3 — count жив внутри
Обработка ошибок: try / catch
Код, который может упасть (запрос к сети, работа с файлом), оборачивают в try, а реакцию на падение кладут в catch:
try {
JSON.parse("это не json");
} catch (err) {
console.error("Не удалось разобрать данные:", err.message);
} finally {
console.log("Выполнится в любом случае");
}
forEach: прогулка по массиву
Выполнить функцию для каждого элемента без ручного цикла:
const fruits = ["яблоко", "банан", "киви"];
fruits.forEach(fruit => {
console.log(fruit.toUpperCase());
});
findIndex: позиция первого совпадения
Найти индекс элемента, который удовлетворяет условию:
const users = [{name: "Аня"}, {name: "Боря"}, {name: "Вера"}];
const index = users.findIndex(u => u.name === "Боря");
// index === 1; если не найден, вернётся -1
every и some: все или некоторые
Проверки, распространяющиеся на всю коллекцию:
const scores = [8, 9, 10, 7];
scores.every(s => s >= 5); // true — все прошли
scores.some(s => s === 10); // true — десяточка есть
Русская сортировка: localeCompare
Стандартная сортировка по юникоду разбросает ё по-своему:
const names = ["Влад", "Аня", "Ёжик", "Боря"];
names.sort((a, b) => a.localeCompare(b, "ru"));
// ["Аня", "Боря", "Влад", "Ёжик"] — по правилам языка
Сортировка чисел
По умолчанию sort сравнивает строки — числа нуждаются в компараторе:
const nums = [10, 2, 33];
nums.sort(); // [10, 2, 33] ой
nums.sort((a, b) => a - b); // [2, 10, 33]
Почему нельзя === массивам
Массивы сравниваются по ссылке, а не по содержимому:
const a = [1, 2];
const b = [1, 2];
a === b; // false — разные «контейнеры»
// сравниваем содержимое по одному элементу:
a.length === b.length && a.every((v, i) => v === b[i]);
Копии массива: slice и spread
Не мутируйте исходник из-за рефакторинга — сначала скопируйте:
const source = [1, 2, 3];
const copy1 = source.slice();
const copy2 = [...source]; // spread, без вложений
copy1.push(4);
source; // [1, 2, 3] — цел
Array.isArray
Как отличить массив от объекта — и почему typeof не поможет:
typeof []; // "object" (мешает)
Array.isArray([]); // true
Array.isArray({}); // false
Порядок чисел подряд
Массив номеров из «дырявого» конструктора строим честно:
const pages = Array.from({ length: 5 }, (_, i) => i + 1);
// [1, 2, 3, 4, 5]
Строка в массив символов
Два способа разгрызть строку:
"привет".split(""); // ["п", "р", ...]
[..."привет"]; // то же, но с эмодзи работает лучше
"а,б,в".split(","); // ["а", "б", "в"]
map с индексом
Второй аргумент — порядковый номер текущего элемента:
const list = ["a", "b"];
list.map((item, i) => `${i + 1}. ${item}`);
// ["1. a", "2. b"]
break для быстрого выхода
Нашли нужное — цикл можно останавливать:
const ids = [10, 20, 30, 40];
let found = null;
for (const id of ids) {
if (id === 30) {
found = id;
break; // дальше не шагаем
}
}
Цепочки: filter().map()
Обработку удобно выстраивать цепочкой вызовов:
const orders = [120, 45, 300, 80];
const big = orders
.filter(x => x >= 100)
.map(x => x * 1.3); // [156, 390]
Среднее по оценкам
Маленький этюд метода reduce — сумма, а затем деление:
const marks = [4, 5, 3, 5];
const avg = marks.reduce((sum, m) => sum + m, 0) / marks.length;
// 4.25
Тренировка
- Напишите функцию
isEven(n), возвращающуюtrueдля чётных чисел. - Выведите через
forстроку из 5 «⭐» (соберите в переменную). - Добавьте
if, который скажет вам, можно ли покупать «взрослые» продукты по возрасту. - Через
mapувеличьте все цены массива на 10%.