Лучшие проекты для портфолио на JavaScript: от новичка до профи

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Почему портфолио решает всё, или как не застрять на уровне «Hello, World»

На собеседованиях по JavaScript работодатель смотрит не на список пройденных курсов, а на три вещи: код, логику и умение доводить дело до конца. Именно проекты для портфолио на JavaScript становятся тем самым мостом между «я знаю теорию» и «я могу решить задачу бизнеса».

Проблема многих новичков — они застревают в бесконечных туториалах. «Сделай 10 проектов за неделю» — звучит круто, но на выходе получается 10 клонов одного и того же калькулятора. Я предлагаю другой путь: 5 проектов, которые реально покажут ваш уровень и закроют 90% требований вакансий Junior/Middle JavaScript Developer.

В этой статье вы найдёте не просто идеи, а готовые архитектурные решения, куски реального кода и объяснение, почему именно этот проект выделит вас среди толпы кандидатов. Поехали?


1. To-Do List с продвинутой логикой: не просто «добавить-удалить»

Самый банальный проект на свете. Но если вы сделаете его как все — вас не заметят. Сделайте Kanban-доску с drag-and-drop на чистом JavaScript. Это покажет, что вы умеете работать с DOM-событиями, LocalStorage и асинхронностью.

Что должно быть внутри

  • Три колонки: «В планах», «В работе», «Готово».
  • Перетаскивание карточек с сохранением позиции в LocalStorage.
  • Фильтрация по тегам (работа/личное/срочно).
  • Тёмная тема (показывает заботу о UX).

Пример реализации drag-and-drop на чистом JS

const draggables = document.querySelectorAll('.task');
const containers = document.querySelectorAll('.column');

draggables.forEach(task => {
    task.addEventListener('dragstart', () => {
        task.classList.add('dragging');
    });

    task.addEventListener('dragend', () => {
        task.classList.remove('dragging');
        saveToLocalStorage(); // кастомная функция сохранения
    });
});

containers.forEach(column => {
    column.addEventListener('dragover', e => {
        e.preventDefault();
        const afterElement = getDragAfterElement(column, e.clientY);
        const draggable = document.querySelector('.dragging');
        if (afterElement == null) {
            column.appendChild(draggable);
        } else {
            column.insertBefore(draggable, afterElement);
        }
    });
});

function getDragAfterElement(container, y) {
    const draggableElements = [...container.querySelectorAll('.task:not(.dragging)')];
    return draggableElements.reduce((closest, child) => {
        const box = child.getBoundingClientRect();
        const offset = y - box.top - box.height / 2;
        if (offset < 0 && offset > closest.offset) {
            return { offset: offset, element: child };
        } else {
            return closest;
        }
    }, { offset: Number.NEGATIVE_INFINITY }).element;
}

Почему это круто: вы показываете понимание событийной модели браузера, работу с координатами и оптимизацию производительности (debounce не нужен, но можно упомянуть в readme).


2. Погодное приложение с геолокацией и анимациями

API-запросы — база современного фронтенда. Проект на JavaScript с использованием fetch, async/await и обработкой ошибок — обязательный пункт в портфолио. Добавьте визуализацию: анимированные облака, дождь или снег на CSS/Canvas.

Ключевые фичи

  • Определение местоположения через Geolocation API.
  • Поиск городов с подсказками (debounce на input).
  • Отображение температуры, влажности, ветра и иконки погоды.
  • График температуры на 5 дней (Chart.js или кастомный SVG).

Пример запроса к OpenWeatherMap

async function getWeather(city) {
    const API_KEY = 'ваш_ключ';
    const url = `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${API_KEY}&units=metric&lang=ru`;

    try {
        const response = await fetch(url);
        if (!response.ok) {
            throw new Error(`Город не найден: ${response.status}`);
        }
        const data = await response.json();
        displayWeather(data);
    } catch (error) {
        showError(error.message);
    }
}

function displayWeather(data) {
    const { temp, humidity } = data.main;
    const { speed } = data.wind;
    const description = data.weather[0].description;

    document.querySelector('.temp').textContent = `${Math.round(temp)}°C`;
    document.querySelector('.humidity').textContent = `Влажность: ${humidity}%`;
    document.querySelector('.wind').textContent = `Ветер: ${speed} м/с`;
    document.querySelector('.desc').textContent = description;
}

Совет: спрячьте API-ключ в переменные окружения или используйте серверную прослойку (например, Netlify Functions). Это покажет, что вы думаете о безопасности.


3. SPA-приложение «Менеджер паролей» (без бэкенда)

Тема безопасности всегда в тренде. Сделайте приложение, которое шифрует пароли с помощью Web Crypto API и хранит их в LocalStorage. Это покажет, что вы разбираетесь в криптографии на уровне браузера.

Архитектура

  • Главный пароль (master password) для доступа.
  • Генератор случайных паролей (с настройками длины и символов).
  • Шифрование AES-GCM перед сохранением.
  • Копирование пароля в буфер обмена одной кнопкой.

Фрагмент шифрования

async function encryptData(plaintext, password) {
    const encoder = new TextEncoder();
    const keyMaterial = await crypto.subtle.importKey(
        'raw',
        encoder.encode(password),
        'PBKDF2',
        false,
        ['deriveKey']
    );

    const key = await crypto.subtle.deriveKey(
        { name: 'PBKDF2', salt: encoder.encode('salt123'), iterations: 100000, hash: 'SHA-256' },
        keyMaterial,
        { name: 'AES-GCM', length: 256 },
        false,
        ['encrypt']
    );

    const iv = crypto.getRandomValues(new Uint8Array(12));
    const encrypted = await crypto.subtle.encrypt(
        { name: 'AES-GCM', iv: iv },
        key,
        encoder.encode(plaintext)
    );

    return { iv: Array.from(iv), data: Array.from(new Uint8Array(encrypted)) };
}

Почему это выделит вас: 90% джунов не знают про SubtleCrypto. Этот проект покажет глубокое понимание безопасности и работы с бинарными данными.


4. Реалтайм-чат на WebSocket (без фреймворков)

Сделайте простой чат с комнатами на WebSocket и Node.js (или Deno). Это покажет, что вы умеете работать с сетевым взаимодействием и серверным JavaScript.

Блоги

Рекомендаций по книгам