Главная Мои проекты Обучение
Главная Мои проекты Обучение

Конспект: Основы программирования (JavaScript)

1. Базовый синтаксис

Переменные

Переменные в JavaScript объявляются с помощью ключевых слов let, const или var. Они используются для хранения данных, таких как числа, строки или объекты.

  • let: позволяет изменять значение переменной, имеет блочную область видимости.
  • const: значение нельзя переопределить, но объекты и массивы можно модифицировать; блочная область видимости.
  • var: устаревший способ объявления с функциональной областью видимости, подверженный "поднятию" (hoisting).

Циклы и условия

Циклы (for, while, do...while) повторяют выполнение кода, а условия (if...else, switch) управляют потоком программы.

// Объявление переменных
let score = 85;
const maxScore = 100;

// Условия
if (score >= 90) {
    console.log("Отлично!");
} else if (score >= 70) {
    console.log("Хорошо.");
} else {
    console.log("Попробуй ещё.");
}

// Цикл for
for (let i = 0; i < 5; i++) {
    console.log(`Итерация ${i}.`);
}

// Цикл while
let count = 0;
while (count < 3) {
    console.log(`Счёт: ${count}.`);
    count++;
}
                    

Примечание:

  • Бесконечные циклы могут зависнуть программу.
  • Используйте let вместо var, чтобы избежать проблем с областью видимости.

2. Функции

Определение и вызов

Функции — это переиспользуемые блоки кода, которые выполняют определённые задачи. Они могут быть объявлены через ключевое слово function, как выражения или с использованием стрелочного синтаксиса.

Рекурсия и замыкания

Рекурсия позволяет функции вызывать саму себя, а замыкания сохраняют доступ к внешним переменным даже после завершения внешней функции.

// Рекурсия: вычисление факториала
function factorial(n) {
    if (n <= 1) return 1;
    return n * factorial(n - 1);
}
console.log(factorial(5)); // 120

// Замыкание: счётчик
function createCounter() {
    let count = 0;
    return function() {
        return count++;
    };
}
const counter = createCounter();
console.log(counter()); // 0
console.log(counter()); // 1

// Стрелочная функция
const multiply = (a, b) => a * b;
console.log(multiply(3, 4)); // 12
                    

Примечание:

  • Глубокая рекурсия может вызвать переполнение стека.
  • Замыкания увеличивают потребление памяти, если используются неправильно.

3. Объектно-ориентированное программирование

Классы и объекты

Объектно-ориентированное программирование (ООП) в JavaScript реализуется через классы, которые определяют шаблоны для создания объектов с общими свойствами и методами.

Наследование и инкапсуляция

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

class Vehicle {
    constructor(brand) {
        this.brand = brand;
    }
    move() {
        console.log(`${this.brand} движется.`);
    }
}

class Car extends Vehicle {
    #fuelLevel = 100; // Приватное поле
    constructor(brand, model) {
        super(brand);
        this.model = model;
    }
    refuel() {
        this.#fuelLevel = 100;
        console.log(`Топливо ${this.model} заправлено.`);
    }
}

const myCar = new Car("Toyota", "Camry");
myCar.move(); // Toyota движется.
myCar.refuel(); // Топливо Camry заправлено.
                    

Примечание:

  • Неправильное использование super вызывает ошибки.
  • Приватные поля (#) не полностью защищены от доступа.

4. Алгоритмы

Сортировки

Алгоритмы сортировки упорядочивают элементы коллекции. Пузырьковая сортировка проста, но неэффективна, тогда как быстрая сортировка быстрее.

Поиск

Алгоритмы поиска находят элементы. Бинарный поиск эффективен для отсортированных массивов.

// Пузырьковая сортировка
function bubbleSort(arr) {
    for (let i = 0; i < arr.length; i++) {
        for (let j = 0; j < arr.length - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
            }
        }
    }
    return arr;
}

// Бинарный поиск
function binarySearch(arr, target) {
    let left = 0, right = arr.length - 1;
    while (left <= right) {
        let mid = Math.floor((left + right) / 2);
        if (arr[mid] === target) return mid;
        if (arr[mid] < target) left = mid + 1;
        else right = mid - 1;
    }
    return -1;
}

console.log(bubbleSort([64, 34, 25, 12, 22])); // [12, 22, 25, 34, 64]
console.log(binarySearch([12, 22, 25, 34, 64], 25)); // 2
                    

Примечание:

  • Пузырьковая сортировка имеет сложность O(n²), что плохо для больших данных.
  • Бинарный поиск требует предварительной сортировки массива.

5. Структуры данных

Массивы и списки

Массивы — упорядоченные коллекции с доступом по индексу. Связные списки реализуются через классы для динамического хранения данных.

Хеш-таблицы

Хеш-таблицы (Map, Set) обеспечивают быстрый доступ к данным по ключу.

// Односвязный список
class Node {
    constructor(data) {
        this.data = data;
        this.next = null;
    }
}

class LinkedList {
    constructor() {
        this.head = null;
    }
    append(data) {
        const node = new Node(data);
        if (!this.head) {
            this.head = node;
            return;
        }
        let current = this.head;
        while (current.next) {
            current = current.next;
        }
        current.next = node;
    }
}

// Хеш-таблица
const users = new Map();
users.set("id1", { name: "Алекс", age: 25 });
console.log(users.get("id1")); // { name: "Алекс", age: 25 }
                    

Примечание:

  • Хеш-таблицы могут иметь коллизии при плохой хеш-функции.
  • Связные списки сложны в управлении из-за указателей.

6. Исключения и обработка ошибок

try...catch

Конструкция try...catch перехватывает ошибки, возникающие во время выполнения кода.

Пользовательские ошибки

Оператор throw позволяет создавать пользовательские ошибки для управления логикой программы.

function fetchData(id) {
    try {
        if (!id) throw new Error("ID не указан.");
        // Имитация запроса
        const data = { id, value: "Данные" };
        console.log(data);
    } catch (error) {
        console.error(`Ошибка: ${error.message}`);
    } finally {
        console.log("Операция завершена.");
    }
}

fetchData(); // Ошибка: ID не указан.
fetchData(1); // { id: 1, value: "Данные" }
                    

Примечание:

  • Неправильная обработка ошибок может скрыть проблемы.
  • Всегда используйте finally для завершающих операций.

7. Основы работы с памятью

Стек и куча

В JavaScript память делится на стек (для примитивов и ссылок) и кучу (для объектов и сложных структур). Стек работает по принципу LIFO, а куча — динамически выделяемая память.

Управление памятью

JavaScript использует автоматическую сборку мусора (Garbage Collection), которая освобождает память от неиспользуемых объектов.

// Примитивы хранятся в стеке
let num = 10; // Стек
let str = "Hello"; // Стек

// Объекты хранятся в куче
let obj = { name: "John" }; // Объект в куче, ссылка в стеке
let arr = [1, 2, 3]; // Массив в куче, ссылка в стеке

// Утечки памяти
function createLeak() {
    const hugeArray = new Array(1000000).fill("leak");
    return function() {
        console.log(hugeArray.length); // Замыкание сохраняет ссылку
    };
}
                    

Примечание:

  • Утечки памяти возникают при сохранении ненужных ссылок (глобальные переменные, замыкания, таймеры).
  • Используйте инструменты DevTools для анализа памяти.

8. Модульность и работа с файлами

Модули ES6

Модули позволяют разделять код на отдельные файлы с экспортом/импортом функциональности. Каждый модуль имеет свою область видимости.

Работа с файловой системой

В Node.js для работы с файлами используются модули fs (синхронные и асинхронные методы) и path для работы с путями.

// math.js - модуль
export const sum = (a, b) => a + b;
export const multiply = (a, b) => a * b;

// app.js - использование модуля
import { sum, multiply } from './math.js';
console.log(sum(2, 3)); // 5

// Работа с файлами в Node.js
import fs from 'fs';
import path from 'path';

// Асинхронное чтение файла
fs.readFile(path.join(__dirname, 'file.txt'), 'utf8', (err, data) => {
    if (err) throw err;
    console.log(data);
});

// Синхронная запись
fs.writeFileSync('output.txt', 'Hello World');
                    

Примечание:

  • Циклические зависимости между модулями могут вызвать ошибки.
  • Асинхронные методы fs предпочтительнее для производительности.

9. Основы многопоточности и асинхронности

Event Loop

JavaScript однопоточен, но использует Event Loop для асинхронных операций. Callback Queue и Microtask Queue определяют порядок выполнения.

Web Workers и Promises

Web Workers позволяют выполнять код в отдельных потоках, а Promises и async/await упрощают работу с асинхронным кодом.

// Event Loop пример
console.log('Start');

setTimeout(() => console.log('Timeout'), 0);
Promise.resolve().then(() => console.log('Promise'));

console.log('End');

// Output: Start, End, Promise, Timeout

Web Worker
// main.js
const worker = new Worker('worker.js');
worker.postMessage('Hello');
worker.onmessage = (e) => console.log(e.data);

// worker.js
onmessage = (e) => {
    console.log(e.data); // "Hello"
    postMessage('World');
};

// Async/Await
async function fetchData() {
    try {
        const response = await fetch('https://api.example.com/data');
        const data = await response.json();
        console.log(data);
    } catch (error) {
        console.error(error);
    }
}
                    

Примечание:

  • Блокировка Event Loop долгими операциями.
  • Web Workers не имеют доступа к DOM.
  • Всегда обрабатывайте ошибки в Promise.

10. Git и GitHub

Основы работы

Git — система контроля версий, а GitHub — платформа для хранения и совместной работы над кодом.

Ветвление и слияние

Ветвление позволяет работать над задачами параллельно, а слияние объединяет изменения в основную ветку.

# Инициализация репозитория
git init
git add .
git commit -m "Начальный коммит."

# Создание и переключение на ветку
git branch feature
git checkout feature

# Добавление изменений
git add .
git commit -m "Добавлена новая функция."

# Слияние ветки
git checkout main
git merge feature

# Отправка на GitHub
git push origin main
                    

Примечание:

  • Конфликты при слиянии требуют ручного разрешения.
  • Используйте понятные сообщения для коммитов.