
Полная версия:
JavaScript: От Основ до Full-Stack Разработки
Пример 4.5.2: Перебор строки
javascript
let text = "JS";
for (let char of text) {
console.log(char);
}
// Вывод:
// J
// S
Когда что использовать:
for...of — для перебора значений элементов массивов, строк и других итерируемых коллекций.
for...in — для перебора ключей (имен свойств) объектов.
Практические задания:Задание 1: Система аутентификации пользователей
javascript
// 1. Напишите функцию checkUserAccess(user), которая принимает объект пользователя
// с полями: role (строка), isActive (булево), subscriptionType (строка)
// 2. Реализуйте проверки:
// - Если пользователь не активен, вернуть "Доступ заблокирован"
// - Если роль "admin", вернуть "Полный доступ"
// - Если роль "user" и подписка "premium", вернуть "Расширенный доступ"
// - Если роль "user" и подписка "basic", вернуть "Базовый доступ"
// - Для всех остальных случаев - "Неизвестная роль"
// 3. Используйте конструкцию if...else if...else
Задание 2: Умный калькулятор скидок
javascript
// 1. Создайте функцию calculateDiscount(price, userType, purchaseCount)
// 2. Реализуйте логику расчета скидки с помощью switch и тернарных операторов:
// Базовая скидка:
// - "vip" - 20%
// - "regular" - 10%
// - "new" - 5%
// Дополнительная скидка за количество покупок:
// - Если purchaseCount > 10 - дополнительно 5%
// - Если purchaseCount > 5 - дополнительно 3%
// 3. Верните итоговую цену и размер скидки в процентах
Задание 3: Анализатор данных массива
javascript
// 1. Создайте функцию analyzeArray(numbers), которая принимает массив чисел
// 2. Используя циклы, найдите:
// - Максимальное и минимальное значение
// - Среднее арифметическое
// - Количество четных и нечетных чисел
// - Все простые числа в массиве
// 3. Верните объект с результатами анализа
Задание 4: Генератор отчетов
javascript
// 1. Дан массив объектов с товарами:
const products = [
{ name: "Телефон", price: 500, category: "electronics", stock: 15 },
{ name: "Книга", price: 20, category: "education", stock: 0 },
{ name: "Наушники", price: 100, category: "electronics", stock: 8 }
];
// 2. Используя циклы и условия, создайте отчеты:
// - Список товаров, которых нет в наличии
// - Общую стоимость всех товаров в категории "electronics"
// - Товары с ценой выше 50 и остатком менее 10
Ответы и решенияРешение задания 1:
javascript
function checkUserAccess(user) {
if (!user.isActive) {
return "Доступ заблокирован";
} else if (user.role === "admin") {
return "Полный доступ";
} else if (user.role === "user") {
return user.subscriptionType === "premium"
? "Расширенный доступ"
: "Базовый доступ";
} else {
return "Неизвестная роль";
}
}
// Примеры использования:
console.log(checkUserAccess({
role: "admin",
isActive: true,
subscriptionType: "premium"
})); // "Полный доступ"
console.log(checkUserAccess({
role: "user",
isActive: true,
subscriptionType: "basic"
})); // "Базовый доступ"
Решение задания 2:
javascript
function calculateDiscount(price, userType, purchaseCount) {
let baseDiscount = 0;
// Базовая скидка по типу пользователя
switch (userType) {
case "vip":
baseDiscount = 20;
break;
case "regular":
baseDiscount = 10;
break;
case "new":
baseDiscount = 5;
break;
default:
baseDiscount = 0;
}
// Дополнительная скидка за количество покупок
let extraDiscount = purchaseCount > 10 ? 5 : purchaseCount > 5 ? 3 : 0;
const totalDiscount = baseDiscount + extraDiscount;
const finalPrice = price * (1 - totalDiscount / 100);
return {
originalPrice: price,
finalPrice: finalPrice,
totalDiscount: totalDiscount,
baseDiscount: baseDiscount,
extraDiscount: extraDiscount
};
}
// Пример использования:
console.log(calculateDiscount(1000, "vip", 12));
// { originalPrice: 1000, finalPrice: 750, totalDiscount: 25, ... }
Решение задания 3:
javascript
function analyzeArray(numbers) {
if (numbers.length === 0) {
return { error: "Массив пуст" };
}
let max = numbers[0];
let min = numbers[0];
let sum = 0;
let evenCount = 0;
let oddCount = 0;
let primes = [];
// Основной цикл анализа
for (let i = 0; i < numbers.length; i++) {
const num = numbers[i];
// Поиск максимума и минимума
if (num > max) max = num;
if (num < min) min = num;
// Сумма для среднего значения
sum += num;
// Четные/нечетные
if (num % 2 === 0) {
evenCount++;
} else {
oddCount++;
}
// Проверка на простое число
if (isPrime(num)) {
primes.push(num);
}
}
return {
max: max,
min: min,
average: sum / numbers.length,
evenCount: evenCount,
oddCount: oddCount,
primes: primes,
totalCount: numbers.length
};
}
// Вспомогательная функция для проверки простых чисел
function isPrime(num) {
if (num < 2) return false;
for (let i = 2; i <= Math.sqrt(num); i++) {
if (num % i === 0) return false;
}
return true;
}
// Пример использования:
console.log(analyzeArray([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]));
Решение задания 4:
javascript
const products = [
{ name: "Телефон", price: 500, category: "electronics", stock: 15 },
{ name: "Книга", price: 20, category: "education", stock: 0 },
{ name: "Наушники", price: 100, category: "electronics", stock: 8 },
{ name: "Ручка", price: 5, category: "education", stock: 50 }
];
// 1. Товары не в наличии
const outOfStock = [];
for (let i = 0; i < products.length; i++) {
if (products[i].stock === 0) {
outOfStock.push(products[i].name);
}
}
// 2. Общая стоимость электроники
let electronicsTotal = 0;
for (let product of products) {
if (product.category === "electronics") {
electronicsTotal += product.price * product.stock;
}
}
// 3. Товары с ценой > 50 и остатком < 10
const criticalProducts = [];
let index = 0;
while (index < products.length) {
const product = products[index];
if (product.price > 50 && product.stock < 10) {
criticalProducts.push({
name: product.name,
price: product.price,
stock: product.stock
});
}
index++;
}
console.log("Нет в наличии:", outOfStock);
console.log("Общая стоимость электроники:", electronicsTotal);
console.log("Критические товары:", criticalProducts);
Чек-лист самопроверки
Я могу создавать сложные условия с помощью if/else и switch
Понимаю разницу между циклами for, while и for...of
Умею использовать тернарный оператор для простых условий
Могу анализировать данные массивов с помощью циклов и условий
Понимаю, когда использовать break и continue в циклах
Эти навыки необходимы для обработки данных, валидации ввода и создания сложной бизнес-логики в реальных приложениях.
Эта глава посвящена логике программы. Условия позволяют нам принимать решения, а циклы — повторять действия. Освоив эти конструкции, вы получите фундаментальные инструменты для создания более сложных и динамичных программ.
Глава 5: Функции: Ваш Инструментарий.
В предыдущих главах мы много говорили о том, как выполнять код последовательно, принимать решения и повторять действия. Но представьте, что нам нужно выполнить один и тот же набор действий в разных частях программы. Копировать и вставлять код — плохая практика. Это делает код громоздким, трудным для чтения и поддержки, и увеличивает риск ошибок.
Решение этой проблемы — функции.
Термин: Функция (Function) — это именованный блок кода, который выполняет определенную задачу. Вы можете “вызвать” функцию по ее имени, чтобы выполнить этот блок кода. Функции позволяют нам:
Повторно использовать код: Написать код один раз и использовать его многократно.
Разбивать большие задачи на мелкие: Делать программу более модульной и понятной.
Улучшать читаемость кода: Давать осмысленные имена блокам кода.
Упрощать тестирование и отладку: Легче тестировать и находить ошибки в небольших, изолированных функциях.
5.1. Создание функций: Function Declaration vs. Function ExpressionЕсть несколько способов определить (объявить) функцию в JavaScript. Два самых распространенных — это Function Declaration и Function Expression.
А) Function Declaration (Объявление функции)
Это стандартный способ объявления функции.
Синтаксис: function имяФункции(параметр1, параметр2, ...) { // тело функции (код) }
function — ключевое слово, которое указывает, что мы объявляем функцию.
имяФункции — уникальное имя, по которому мы будем вызывать функцию. Следуйте правилам именования переменных (обычно CamelCase, например, calculateSum).
параметр1, параметр2, ... — это параметры функции. Они действуют как временные переменные, которые получают значения, передаваемые в функцию при ее вызове. Параметры необязательны; функция может не принимать никаких аргументов.
{ // тело функции } — блок кода, который будет выполнен при вызове функции.
Пример 5.1.1: Функция приветствия
javascript
function greetUser() {
console.log("Приветствую тебя!");
}
// Вызов функции:
greetUser(); // Выведет: Приветствую тебя!
greetUser(); // Можно вызвать несколько раз
Пример 5.1.2: Функция с параметрами
javascript
function greetUserByName(name) { // name - параметр
console.log(`Приветствую, ${name}!`);
}
greetUserByName("Алиса"); // Выведет: Приветствую, Алиса!
greetUserByName("Боб"); // Выведет: Приветствую, Боб!
Когда мы вызываем greetUserByName("Алиса"), строка "Алиса" передается как аргумент в функцию, и внутри функции переменная name получает значение "Алиса".
Поднятие (Hoisting): Одна из особенностей Function Declaration в JavaScript — это “поднятие”. Это означает, что функция, объявленная таким образом, доступна для вызова до того, как она фактически объявлена в коде.
javascript
sayHello(); // Это сработает!
function sayHello() {
console.log("Привет!");
}
JavaScript “поднимает” объявление функции sayHello в начало области видимости. Это удобно, но иногда может сбивать с толку начинающих, поэтому стоит помнить об этом.
Б) Function Expression (Выражение функции)
При таком подходе функция определяется как часть выражения (обычно присваивается переменной).
Синтаксис: let имяПеременной = function(параметр1, ...) { // тело функции };
javascript
let greetSomeone = function(name) {
console.log(`Приветствую, ${name}!`);
};
// Вызов функции:
greetSomeone("Чарли"); // Выведет: Приветствую, Чарли!
Основные отличия от Function Declaration:
Поднятие: Функции, определенные как Function Expression, не поднимаются так же, как Function Declaration. Если вы попытаетесь вызвать такую функцию до ее объявления, вы получите ошибку TypeError.javascript// sayGoodbye(); // Ошибка! TypeError: sayGoodbye is not a function
let sayGoodbye = function(name) {
console.log(`До свидания, ${name}!`);
};
sayGoodbye("Дэвид"); // Теперь сработает
Анонимные функции: Function Expression может быть анонимной (без имени), как в примере greetSomeone. Это часто используется при передаче функций в качестве аргументов другим функциям (например, в обработчиках событий или при использовании методов массивов).
5.2. Стрелочные функции (Arrow Functions)С появлением стандарта ES6 (ECMAScript 2015) были введены стрелочные функции — более краткий и удобный синтаксис для записи функций, особенно для простых случаев.
Синтаксис (основные варианты):
С одним параметром (или без параметров) и одним выражением в теле: Скобки вокруг параметра и фигурные скобки {} опускаются. Результат выражения возвращается автоматически.javascript// Было:
// let greetUserByName = function(name) {
// return `Приветствую, ${name}!`;
// };
// Стало (стрелочная функция):
let greetUserByName = name => `Приветствую, ${name}!`; // скобки вокруг name опущены
console.log(greetUserByName("Ева")); // Выведет: Приветствую, Ева!
// Без параметров:
// let showMessage = function() { return "Сообщение!"; };
let showMessage = () => "Сообщение!"; // Скобки для параметров обязательны, если их нет
console.log(showMessage()); // Выведет: Сообщение!
С несколькими параметрами или несколькими выражениями в теле: Параметры заключаются в скобки, а тело функции — в фигурные скобки {}. В этом случае нужно явно использовать return, если вы хотите вернуть значение.javascript// Было:
// let calculateSum = function(a, b) {
// let sum = a + b;
// return sum;
// };
// Стало (стрелочная функция):
let calculateSum = (a, b) => { // скобки для параметров обязательны
let sum = a + b;
return sum; // return нужен, так как тело функции больше одного выражения
};
console.log(calculateSum(5, 3)); // Выведет: 8
Важные особенности стрелочных функций:
Краткость: Особенно удобны для простых функций.
Отсутствие this: Стрелочные функции не имеют своего собственного контекста this. Они “захватывают” this из окружающей (лексической) области видимости. Это одно из самых важных отличий и делает их очень полезными в определенных ситуациях (например, при работе с методами объектов или внутри обработчиков событий). Мы подробно разберем this позже.
Не подходят для: Методов объектов (если вы хотите, чтобы this ссылался на сам объект), конструкторов (функций, вызываемых с new).
5.3. Параметры и аргументы функций
Мы уже мельком коснулись параметров и аргументов. Давайте разберемся подробнее.
Параметры (Parameters): Имена переменных, перечисленные в определении функции. Они действуют как “приемники” для входящих данных.
Аргументы (Arguments): Фактические значения, которые передаются в функцию при ее вызове.
javascript
function multiply(num1, num2) { // num1 и num2 - ПАРАМЕТРЫ
let result = num1 * num2;
console.log(`Результат умножения ${num1} на ${num2} равен ${result}`);
}
multiply(5, 3); // 5 и 3 - АРГУМЕНТЫ. num1 станет 5, num2 станет 3.
multiply(10, 2); // 10 и 2 - АРГУМЕНТЫ. num1 станет 10, num2 станет 2.
Что происходит, если аргументов меньше или больше, чем параметров?
Недостаточно аргументов: Если вы передали меньше аргументов, чем параметров, недостающие параметры получат значение undefined.javascriptfunction greet(firstName, lastName) {
console.log(`Привет, ${firstName} ${lastName}`);
}
greet("Алиса"); // Выведет: Привет, Алиса undefined
Чтобы избежать этого, можно использовать значения параметров по умолчанию (ES6).javascriptfunction greetWithDefault(firstName, lastName = "Гость") { // lastName по умолчанию "Гость"
console.log(`Привет, ${firstName} ${lastName}`);
}
greetWithDefault("Алиса"); // Привет, Алиса Гость
greetWithDefault("Боб", "Смит"); // Привет, Боб Смит
Слишком много аргументов: Если вы передали больше аргументов, чем параметров, “лишние” аргументы просто игнорируются (если вы не используете специальные техники, такие как arguments или rest-параметры).javascriptfunction addTwoNumbers(a, b) {
console.log(a + b);
}
addTwoNumbers(2, 3, 100); // Выведет: 5 (аргумент 100 проигнорирован)
Термин: Аргументы по умолчанию (Default Parameters) — возможность задать значения для параметров функции, которые будут использоваться, если при вызове функции соответствующие аргументы не были переданы.
Термин: Rest-параметры (Rest Parameters) ... (ES6) — Позволяют представить неизвестное количество аргументов как массив. Это более гибкая альтернатива старому объекту arguments.
javascript
function sumAll(...numbers) { // numbers будет массивом всех переданных аргументов
let total = 0;
for (let num of numbers) {
total += num;
}
return total;
}
console.log(sumAll(1, 2, 3)); // Выведет: 6
console.log(sumAll(10, 20, 30, 40)); // Выведет: 100
console.log(sumAll()); // Выведет: 0
Rest-параметры должны быть последними в списке параметров.
5.4. Возвращаемые значения (return)Функции не только выполняют действия, но и могут возвращать результат своей работы. Это делается с помощью ключевого слова return.
Когда return выполняется, функция немедленно завершает свою работу, и значение, указанное после return, передается обратно в то место, откуда функция была вызвана.
Если в функции нет return, или return используется без значения, функция неявно возвращает undefined.
Пример 5.4.1: Функция, возвращающая результат
javascript
function calculateArea(width, height) {
if (width <= 0 || height <= 0) {
console.error("Ширина и высота должны быть положительными числами.");
return undefined; // Явно возвращаем undefined в случае ошибки
}
let area = width * height;
return area; // Возвращаем вычисленное значение
}
let rectangle1Area = calculateArea(10, 5); // 50 будет присвоено rectangle1Area
console.log("Площадь 1:", rectangle1Area); // Площадь 1: 50
let rectangle2Area = calculateArea(8, 4);
console.log("Площадь 2:", rectangle2Area); // Площадь 2: 32
let invalidArea = calculateArea(-2, 5); // Выведет ошибку в консоль
console.log("Некорректная площадь:", invalidArea); // Некорректная площадь: undefined
Пример 5.4.2: Функция, не возвращающая значения (неявно возвращает undefined)
javascript
function displayMessage(msg) {
console.log("Сообщение: " + msg);
// Нет return
}
let result = displayMessage("Привет!"); // result будет undefined
console.log("Результат вызова функции:", result); // Результат вызова функции: undefined
5.5. Область видимости (Scope)
Мы уже касались области видимости let и const (блочная) и var (функциональная). Давайте углубимся.
Термин: Область видимости (Scope) — это набор правил, определяющий, где в вашем коде доступны переменные и функции.
JavaScript имеет две основные области видимости:
Глобальная область видимости (Global Scope): Переменные, объявленные вне каких-либо функций или блоков, находятся в глобальной области видимости. Они доступны из любой части вашего кода. В браузере глобальный объект — это window.
Локальная область видимости (Local Scope):Функциональная область видимости: Переменные, объявленные с помощью var внутри функции, доступны только внутри этой функции.
Блочная область видимости: Переменные, объявленные с помощью let и const внутри блока кода (например, {...} внутри if, for, или просто отдельный блок), доступны только внутри этого блока.
Пример 5.5.1: Демонстрация областей видимости
javascript
// Глобальная переменная
let globalVar = "Я глобальный";
function myFunction() {
// Локальная переменная для myFunction
let localVar = "Я локальный для myFunction";
console.log(globalVar); // Доступ к глобальной переменной
console.log(localVar); // Доступ к локальной переменной
if (true) {
// Блочная переменная
let blockVar = "Я внутри блока if";
console.log(blockVar); // Доступ к блочной переменной
console.log(localVar); // Доступ к локальной переменной функции
}
// console.log(blockVar); // Ошибка! blockVar не виден вне блока if
}
myFunction();
console.log(globalVar); // Доступ к глобальной переменной
// console.log(localVar); // Ошибка! localVar не виден вне myFunction
Принцип минимизации области видимости: Старайтесь делать переменные максимально локальными (внутри функций или блоков, где они нужны). Это предотвращает случайные изменения значений из других частей программы и делает код более понятным.
Термин: Замыкание (Closure) — более продвинутая концепция, связанная с областями видимости. Это функция, которая “помнит” переменные из той области видимости, в которой она была создана, даже если эта область видимости уже не активна. Мы подробно разберем замыкания позже, но важно понимать, что функции имеют доступ к переменным из внешних областей видимости.
Практическое задание:
Задание 1: Валидатор данных формы
javascript
// 1. Создайте функцию validateEmail(email), которая проверяет:
// - Наличие символа @
// - Длину доменной части не менее 2 символов
// - Возвращает true/false
// 2. Создайте функцию validatePassword(password, minLength = 8), которая:
// - Проверяет длину пароля
// - Проверяет наличие хотя бы одной цифры
// - Возвращает объект { isValid: boolean, errors: [] }
Задание 2: Генератор контента для интерфейса
javascript
// 1. Создайте функцию createUserCard(userData), которая принимает объект с данными:
// { name, email, avatar, isOnline }
// 2. Функция должна ВОЗВРАЩАТЬ HTML-строку для карточки пользователя:
// - Если isOnline = true, добавить класс 'online'
// - Если avatar отсутствует, использовать аватар по умолчанию
// - Использовать значения по умолчанию для отсутствующих полей

