Основы JavaScript

JavaScript — это язык программирования, который делает веб-страницы интерактивными.

Переменные

Переменные хранят данные, которые можно использовать в программе.

Объявление переменных:

// let - можно изменять
let name = "Иван";
name = "Петр"; // OK

// const - нельзя изменять
const age = 30;
// age = 31; // Ошибка!

// var - устаревший способ (не рекомендуется)
var oldVar = "устарело";

Совет: Всегда используйте const по умолчанию, и только let если переменная будет изменяться.

Типы данных

JavaScript имеет несколько примитивных типов данных:

// String (строка)
const str = "Привет мир";

// Number (число)
const num = 42;
const float = 3.14;

// Boolean (логический)
const isTrue = true;
const isFalse = false;

// null и undefined
const empty = null;
const notDefined = undefined;

// Symbol (уникальный идентификатор)
const sym = Symbol('описание');

// BigInt (большие числа)
const bigNum = 123456789012345678901234567890n;

Операторы

JavaScript поддерживает различные операторы для работы с данными:

// Арифметические
let sum = 10 + 5; // 15
let diff = 10 - 5; // 5
let product = 10 * 5; // 50
let quotient = 10 / 5; // 2
let remainder = 10 % 3; // 1

// Сравнения
10 == '10'; // true (нестрогое)
10 === '10'; // false (строгое)
10 != '10'; // false
10 !== '10'; // true

// Логические
true && false; // false (И)
true || false; // true (ИЛИ)
!true; // false (НЕ)

Функции

Функции позволяют группировать код для многократного использования.

Объявление функций

// Function Declaration
function greet(name) {
    return `Привет, ${name}!`;
}

// Function Expression
const greet2 = function(name) {
    return `Привет, ${name}!`;
};

// Вызов функций
greet("Иван"); // "Привет, Иван!"
greet2("Петр"); // "Привет, Петр!"

Стрелочные функции (ES6)

Стрелочные функции имеют более короткий синтаксис и не имеют своего this.

// Стандартная функция
const sum = function(a, b) {
    return a + b;
};

// Стрелочная функция
const sumArrow = (a, b) => a + b;

// Если один параметр - скобки можно опустить
const square = x => x * x;

// Если нет параметров
const sayHi = () => console.log("Привет!");

// Многострочная функция
const multiply = (a, b) => {
    const result = a * b;
    return result;
};

Параметры и аргументы

// Параметры по умолчанию
function greet(name = "Гость") {
    console.log(`Привет, ${name}!`);
}

greet(); // Привет, Гость!
greet("Иван"); // Привет, Иван!

// Rest параметры
function sumAll(...numbers) {
    return numbers.reduce((sum, num) => sum + num, 0);
}

sumAll(1, 2, 3); // 6
sumAll(1, 2, 3, 4, 5); // 15

Работа с DOM

DOM (Document Object Model) - это программный интерфейс для HTML и XML документов.

Поиск элементов

// Поиск по id
const header = document.getElementById('header');

// Поиск по CSS-селектору (первый элемент)
const btn = document.querySelector('.btn');

// Поиск по CSS-селектору (все элементы)
const items = document.querySelectorAll('.item');

// Поиск по тегу
const divs = document.getElementsByTagName('div');

// Поиск по классу
const buttons = document.getElementsByClassName('btn');

Изменение DOM

// Создание элемента
const newDiv = document.createElement('div');
newDiv.textContent = 'Новый элемент';

// Добавление в DOM
document.body.appendChild(newDiv);

// Изменение стилей
newDiv.style.color = 'red';
newDiv.style.fontSize = '20px';

// Изменение классов
newDiv.classList.add('active');
newDiv.classList.remove('inactive');
newDiv.classList.toggle('hidden');

// Удаление элемента
newDiv.remove();

Работа с атрибутами

const link = document.querySelector('a');

// Получение атрибута
const href = link.getAttribute('href');

// Установка атрибута
link.setAttribute('href', 'https://example.com');
link.setAttribute('target', '_blank');

// Проверка наличия атрибута
if (link.hasAttribute('target')) {
    console.log('Есть target атрибут');
}

// Удаление атрибута
link.removeAttribute('target');

// data-атрибуты
const userDiv = document.querySelector('[data-user-id]');
const userId = userDiv.dataset.userId; // Получение
userDiv.dataset.userStatus = 'active'; // Установка

События

JavaScript может реагировать на действия пользователя с помощью событий.

Обработка событий

const button = document.querySelector('#myButton');

// Добавление обработчика события
button.addEventListener('click', function(event) {
    console.log('Кнопка нажата!', event);
});

// Удаление обработчика
const handleClick = () => console.log('Клик!');
button.addEventListener('click', handleClick);
button.removeEventListener('click', handleClick);

// Объект события
document.addEventListener('mousemove', (e) => {
    console.log(`X: ${e.clientX}, Y: ${e.clientY}`);
});

Основные события

Событие Описание
click Клик мышью по элементу
dblclick Двойной клик
mouseenter Курсор над элементом
mouseleave Курсор покинул элемент
keydown Клавиша нажата
keyup Клавиша отпущена
submit Отправка формы
change Изменение значения элемента формы
load Завершение загрузки элемента

Делегирование событий

Делегирование позволяет обрабатывать события на динамически создаваемых элементах.

// Вместо добавления обработчика каждому элементу
document.querySelectorAll('.item').forEach(item => {
    item.addEventListener('click', handleClick);
});

// Используем делегирование (один обработчик на родителе)
document.querySelector('.list').addEventListener('click', (e) => {
    if (e.target.classList.contains('item')) {
        console.log('Клик по элементу:', e.target);
    }
});

Массивы

Массивы используются для хранения упорядоченных коллекций данных.

Создание и основные методы

// Создание массива
const fruits = ['Яблоко', 'Банан'];

// Доступ к элементам
fruits[0]; // 'Яблоко'
fruits.length; // 2

// Добавление/удаление элементов
fruits.push('Апельсин'); // ['Яблоко', 'Банан', 'Апельсин']
fruits.pop(); // Удаляет 'Апельсин'
fruits.unshift('Груша'); // ['Груша', 'Яблоко', 'Банан']
fruits.shift(); // Удаляет 'Груша'

// Поиск в массиве
fruits.indexOf('Банан'); // 1
fruits.includes('Яблоко'); // true

// Объединение массивов
const moreFruits = ['Ананас', 'Манго'];
const allFruits = fruits.concat(moreFruits);

Итерация по массиву

const numbers = [1, 2, 3, 4, 5];

// forEach - выполнить функцию для каждого элемента
numbers.forEach(num => console.log(num));

// map - создать новый массив
const doubled = numbers.map(num => num * 2);

// filter - отфильтровать элементы
const evens = numbers.filter(num => num % 2 === 0);

// reduce - свертка массива
const sum = numbers.reduce((total, num) => total + num, 0);

// some/every - проверка условий
const hasEven = numbers.some(num => num % 2 === 0);
const allPositive = numbers.every(num => num > 0);

Деструктуризация массивов

const rgb = [255, 128, 0];

// Стандартный способ
const red = rgb[0];
const green = rgb[1];
const blue = rgb[2];

// Деструктуризация
const [r, g, b] = rgb;

// Пропуск элементов
const [first, , third] = ['a', 'b', 'c']; // first='a', third='c'

// Остаточные параметры
const [head, ...tail] = [1, 2, 3, 4]; // head=1, tail=[2, 3, 4]

Объекты

Объекты используются для хранения коллекций данных и более сложных структур.

Создание и работа с объектами

// Создание объекта
const person = {
    name: 'Иван',
    age: 30,
    greet() {
        console.log(`Привет, меня зовут ${this.name}`);
    }
};

// Доступ к свойствам
person.name; // 'Иван'
person['age']; // 30

// Добавление/изменение свойств
person.job = 'Разработчик';
person.age = 31;

// Удаление свойств
delete person.job;

// Проверка наличия свойства
'name' in person; // true
person.hasOwnProperty('age'); // true

// Вызов метода
person.greet(); // "Привет, меня зовут Иван"

Деструктуризация объектов

const user = {
    id: 1,
    name: 'Иван',
    age: 30,
    email: 'ivan@example.com'
};

// Стандартный способ
const name = user.name;
const age = user.age;

// Деструктуризация
const { name, age } = user;

// С новыми именами переменных
const { name: userName, age: userAge } = user;

// Значения по умолчанию
const { name, age, isAdmin = false } = user;

// Вложенные объекты
const userWithAddress = {
    name: 'Петр',
    address: {
        city: 'Москва',
        street: 'Ленина'
    }
};
const { address: { city } } = userWithAddress;

Методы объектов

const person = {
    name: 'Мария',
    age: 25
};

// Получение ключей
Object.keys(person); // ['name', 'age']

// Получение значений
Object.values(person); // ['Мария', 25]

// Получение пар [ключ, значение]
Object.entries(person); // [['name', 'Мария'], ['age', 25]]

// Копирование объекта
const clone = Object.assign({}, person);
const modernClone = { ...person }; // Spread оператор

// Заморозка объекта (нельзя изменять)
const frozen = Object.freeze(person);

Асинхронность

JavaScript использует асинхронную модель выполнения для работы с долгими операциями.

Callback-функции

// Пример с setTimeout
setTimeout(() => {
    console.log('Это сообщение появится через 1 секунду');
}, 1000);

// Пример с callback
function loadData(callback) {
    setTimeout(() => {
        callback('Данные загружены');
    }, 2000);
}

loadData((result) => {
    console.log(result); // "Данные загружены" (через 2 секунды)
});

// Проблема callback hell
loadData((data) => {
    processData(data, (processed) => {
        saveData(processed, (saved) => {
            console.log('Готово:', saved);
        });
    });
});

Промисы (Promises)

// Создание промиса
const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
        const success = Math.random() > 0.5;
        if (success) {
            resolve('Успех!');
        } else {
            reject('Ошибка!');
        }
    }, 1000);
});

// Использование промиса
promise
    .then(result => {
        console.log(result); // "Успех!"
    })
    .catch(error => {
        console.error(error); // "Ошибка!"
    })
    .finally(() => {
        console.log('Завершено в любом случае');
    });

// Цепочка промисов
fetchData()
    .then(processData)
    .then(saveData)
    .then(result => console.log(result))
    .catch(error => console.error(error));

Fetch API

// GET запрос
fetch('https://api.example.com/data')
    .then(response => {
        if (!response.ok) {
            throw new Error('Ошибка сети');
        }
        return response.json();
    })
    .then(data => {
        console.log(data);
    })
    .catch(error => {
        console.error('Ошибка:', error);
    });

// POST запрос
fetch('https://api.example.com/data', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json'
    },
    body: JSON.stringify({
        name: 'Иван',
        age: 30
    })
})
.then(response => response.json())
.then(data => console.log(data));

Async/Await

// Асинхронная функция
async function loadUserData(userId) {
    try {
        const response = await fetch(`https://api.example.com/users/${userId}`);
        if (!response.ok) {
            throw new Error('Пользователь не найден');
        }
        const user = await response.json();
        return user;
    } catch (error) {
        console.error('Ошибка загрузки:', error);
        throw error;
    }
}

// Использование
async function displayUser(userId) {
    try {
        const user = await loadUserData(userId);
        console.log('Пользователь:', user);
    } catch (error) {
        console.error('Не удалось загрузить пользователя');
    }
}

displayUser(123);

Современный JavaScript (ES6+)

Новые возможности JavaScript, добавленные в ES6 и более поздних версиях.

Классы

class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }

    greet() {
        console.log(`Привет, меня зовут ${this.name}`);
    }

    static createDefault() {
        return new Person('Гость', 18);
    }
}

// Создание экземпляра
const ivan = new Person('Иван', 30);
ivan.greet(); // "Привет, меня зовут Иван"

// Наследование
class Employee extends Person {
    constructor(name, age, position) {
        super(name, age);
        this.position = position;
    }

    introduce() {
        console.log(`Я ${this.name}, работаю ${this.position}`);
    }
}

const manager = new Employee('Мария', 25, 'менеджером');
manager.introduce(); // "Я Мария, работаю менеджером"

Модули

// math.js
export const PI = 3.14159;

export function sum(a, b) {
    return a + b;
}

export default class Calculator {
    multiply(a, b) {
        return a * b;
    }
}

// app.js
import { PI, sum } from './math.js';
import Calculator from './math.js';

console.log(PI); // 3.14159
console.log(sum(2, 3)); // 5

const calc = new Calculator();
console.log(calc.multiply(4, 5)); // 20

Spread и Rest операторы

// Spread для массивов
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = [...arr1, ...arr2]; // [1, 2, 3, 4, 5, 6]

// Spread для объектов
const obj1 = { a: 1, b: 2 };
const obj2 = { c: 3, d: 4 };
const merged = { ...obj1, ...obj2 }; // { a: 1, b: 2, c: 3, d: 4 }

// Rest параметры в функциях
function sum(...numbers) {
    return numbers.reduce((total, num) => total + num, 0);
}

sum(1, 2, 3, 4); // 10

Практические примеры

Реальные примеры использования JavaScript в веб-разработке.

Создание модального окна

// HTML
<button id="openModal">Открыть модальное окно</button>
<div id="modal" class="modal hidden">
    <div class="modal-content">
        <span class="close">×</span>
        <p>Это модальное окно!</p>
    </div>
</div>

// CSS
.modal {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0,0,0,0.5);
    display: flex;
    justify-content: center;
    align-items: center;
}
.modal-content {
    background: white;
    padding: 20px;
    border-radius: 5px;
    position: relative;
}
.close {
    position: absolute;
    top: 10px;
    right: 10px;
    cursor: pointer;
}
.hidden {
    display: none;
}

// JavaScript
const modal = document.getElementById('modal');
const openBtn = document.getElementById('openModal');
const closeBtn = modal.querySelector('.close');

openBtn.addEventListener('click', () => {
    modal.classList.remove('hidden');
});

closeBtn.addEventListener('click', () => {
    modal.classList.add('hidden');
});

modal.addEventListener('click', (e) => {
    if (e.target === modal) {
        modal.classList.add('hidden');
    }
});

Валидация формы

// HTML
<form id="signupForm">
    <input type="text" id="username" placeholder="Имя пользователя" required>
    <input type="email" id="email" placeholder="Email" required>
    <input type="password" id="password" placeholder="Пароль" required minlength="6">
    <button type="submit">Зарегистрироваться</button>
</form>
<div id="errors"></div>

const form = document.getElementById('signupForm');
const errorsContainer = document.getElementById('errors');

form.addEventListener('submit', (e) => {
    e.preventDefault();
    errorsContainer.innerHTML = '';
    
    const username = form.username.value.trim();
    const email = form.email.value.trim();
    const password = form.password.value;
    
    const errors = [];
    
    if (username.length < 3) {
        errors.push('Имя должно быть не менее 3 символов');
    }
    
    if (!email.includes('@')) {
        errors.push('Введите корректный email');
    }
    
    if (password.length < 6) {
        errors.push('Пароль должен быть не менее 6 символов');
    }
    
    if (errors.length > 0) {
        errors.forEach(error => {
            const errorElement = document.createElement('p');
            errorElement.textContent = error;
            errorElement.style.color = 'red';
            errorsContainer.appendChild(errorElement);
        });
    } else {
        alert('Форма успешно отправлена!');
        form.reset();
    }
});

Загрузка данных с сервера

// HTML
<button id="loadUsers">Загрузить пользователей</button>
<ul id="usersList"></ul>

// JavaScript
const loadBtn = document.getElementById('loadUsers');
const usersList = document.getElementById('usersList');

async function fetchUsers() {
    try {
        const response = await fetch('https://jsonplaceholder.typicode.com/users');
        if (!response.ok) {
            throw new Error('Ошибка загрузки данных');
        }
        const users = await response.json();
        return users;
    } catch (error) {
        console.error('Ошибка:', error);
        return [];
    }
}

function renderUsers(users) {
    usersList.innerHTML = '';
    users.forEach(user => {
        const li = document.createElement('li');
        li.textContent = `${user.name} (${user.email})`;
        usersList.appendChild(li);
    });
}

loadBtn.addEventListener('click', async () => {
    const users = await fetchUsers();
    renderUsers(users);
});

// Добавим индикатор загрузки
loadBtn.addEventListener('click', async () => {
    try {
        // Показываем индикатор загрузки
        loadBtn.disabled = true;
        loadBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Загрузка...';
        
        const users = await fetchUsers();
        renderUsers(users);
        
        // Добавляем кнопку очистки
        if (users.length > 0) {
            const clearBtn = document.createElement('button');
            clearBtn.textContent = 'Очистить список';
            clearBtn.className = 'clear-btn';
            clearBtn.style.marginLeft = '10px';
            
            clearBtn.addEventListener('click', () => {
                usersList.innerHTML = '';
                clearBtn.remove();
            });
            
            loadBtn.insertAdjacentElement('afterend', clearBtn);
        }
    } catch (error) {
        console.error('Ошибка:', error);
        const errorElement = document.createElement('p');
        errorElement.textContent = 'Не удалось загрузить пользователей';
        errorElement.style.color = 'red';
        usersList.appendChild(errorElement);
    } finally {
        // Восстанавливаем кнопку
        loadBtn.disabled = false;
        loadBtn.innerHTML = 'Загрузить пользователей';
    }
});

// Добавим стили для кнопок через JavaScript
const style = document.createElement('style');
style.textContent = `
    #loadUsers, .clear-btn {
        padding: 10px 15px;
        background-color: #4361ee;
        color: white;
        border: none;
        border-radius: 5px;
        cursor: pointer;
        font-size: 1rem;
        transition: background-color 0.3s;
    }
    
    #loadUsers:hover, .clear-btn:hover {
        background-color: #3a56d4;
    }
    
    #loadUsers:disabled {
        background-color: #6c757d;
        cursor: not-allowed;
    }
    
    #usersList {
        margin-top: 20px;
        list-style: none;
    }
    
    #usersList li {
        padding: 10px;
        border-bottom: 1px solid #eee;
    }
    
    #usersList li:last-child {
        border-bottom: none;
    }
`;
document.head.appendChild(style);