Основы 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("Петр"); // "Привет, Петр!"
Стрелочные функции имеют более короткий синтаксис и не имеют своего 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');
// Создание элемента
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 использует асинхронную модель выполнения для работы с долгими операциями.
// Пример с 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);
});
});
});
// Создание промиса
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));
// 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 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 для массивов
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);