Дополнительные функции обратного вызова!
Иногда функция должна быть универсальной и вызывать колбэк только если он передан, при этом не увеличивая код проверками:
В JS это делается напрямую через optional chaining, без условий и лишней логики:
Если колбэк не передан, код просто пропускается, если передан — вызывается как обычная функция:
🔥 Такой приём позволяет проектировать API с опциональным поведением без перегрузок функций и условий.
📣 JS Ready | #совет
Иногда функция должна быть универсальной и вызывать колбэк только если он передан, при этом не увеличивая код проверками:
if (callback) {
callback(data);
}В JS это делается напрямую через optional chaining, без условий и лишней логики:
callback?.(data);
Если колбэк не передан, код просто пропускается, если передан — вызывается как обычная функция:
fetchData('/api/user');
fetchData('/api/user', data => console.log(data));Please open Telegram to view this post
VIEW IN TELEGRAM
👍14❤9🤝8
This media is not supported in your browser
VIEW IN TELEGRAM
Markdown Preview Enhanced — расширяет стандартный предпросмотр Markdown в VS Code. Поддерживает диаграммы, формулы, графики, Mermaid, подсветку кода, экспорт в PDF и HTML. Сразу видишь, как будет выглядеть README, документация или статья, без внешних инструментов и лишних шагов.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15❤6🤝5
Реализуем древовидную структуру, моделирующую файловую систему, и напишем универсальный механизм поиска по этому дереву.
В этой задаче:
• Работаем с вложенными объектами как с деревом;
• Реализуем рекурсивный обход;
• Строим чистую функцию поиска без глобального состояния;
• Разделяем механизм обхода и критерий фильтрации.
Это разбор базового паттерна обхода структур, который лежит в основе множества реальных инструментов.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
❤14👍9🔥8🤝1
This media is not supported in your browser
VIEW IN TELEGRAM
Здесь по шагам объясняют, как создаются html-страницы, как работают теги, формы, таблицы, семантика. А также как оформлять всё это с помощью CSS: селекторы, цвета, layout, Flexbox, Grid и адаптивный дизайн. Материалы поданы простым языком и с примерами, удобно для новичков и тех, кто хочет повторить базу.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤14🔥9👍7
Простой поиск по массиву объектов с поддержкой нескольких полей!
Частая задача в интерфейсах — быстрый клиентский поиск: таблицы, списки пользователей, товары. Ниже — универсальная функция фильтрации без библиотек для substring-поиска по нескольким полям.
Допустим, есть массив:
Требование: регистронезависимый поиск по
Функция поиска:
Использование:
Поиск работает через
Если пользователь вводит несколько слов, часто логично требовать совпадение каждого, но разрешать нахождение слов в разных полях:
Здесь:
alex совпадает в
🔥 Для списков до нескольких тысяч элементов обычно достаточно без сторонних библиотек. Если данных больше или поиск вызывается очень часто — имеет смысл кэшировать нормализованные значения или строить индекс.
📣 JS Ready | #практика
Частая задача в интерфейсах — быстрый клиентский поиск: таблицы, списки пользователей, товары. Ниже — универсальная функция фильтрации без библиотек для substring-поиска по нескольким полям.
Допустим, есть массив:
const users = [
{ id: 1, name: "Alex Ivanov", email: "alex@mail.com" },
{ id: 2, name: "Maria Petrova", email: "maria@mail.com" },
{ id: 3, name: "John Smith", email: "john@mail.com" }
];
Требование: регистронезависимый поиск по
name и email с частичным совпадением.Функция поиска:
function normalize(value) {
return String(value ?? "")
.toLowerCase()
// Удаление диакритики (если это нужно в проекте)
.normalize("NFKD")
.replace(/[\u0300-\u036f]/g, "");
}
function search(items, query, fields) {
const q = normalize(query).trim();
if (!q) return items;
return items.filter(item =>
fields.some(field => normalize(item[field]).includes(q))
);
}normalize делает безопасное приведение к строке, единый регистр и (опционально) удаление диакритики. trim() исключает пустые запросы, some реализует OR по полям.Использование:
console.log(search(users, "alex", ["name", "email"]));
// [{ id: 1, name: "Alex Ivanov", ... }]
console.log(search(users, "mail.com", ["name", "email"]));
// все пользователи
Поиск работает через
includes, поэтому это именно substring-поиск: частичные совпадения, простое поведение.Если пользователь вводит несколько слов, часто логично требовать совпадение каждого, но разрешать нахождение слов в разных полях:
function searchMulti(items, query, fields) {
const tokens = normalize(query)
.trim()
.split(/\s+/)
.filter(Boolean);
if (!tokens.length) return items;
return items.filter(item =>
tokens.every(token =>
fields.some(field => normalize(item[field]).includes(token))
)
);
}Здесь:
every задаёт AND по словам запроса, some сохраняет OR по полям.searchMulti(users, "alex mail", ["name", "email"]);
alex совпадает в
name, mail — в email, поэтому объект будет найден.Please open Telegram to view this post
VIEW IN TELEGRAM
🤝10👍9🔥8❤3
This media is not supported in your browser
VIEW IN TELEGRAM
Faker — позволяет легко вставлять случайные имена, адреса, номера телефонов, даты и другие данные прямо в ваш код.
Очень удобно при разработке и тестировании, особенно если нужно наполнить макеты реалистичными значениями.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥19👍12🤝7❤1
FormData — нативная работа с данными форм и файлами!
Создание
В
Пример 1 — чтение значений:
Пример 2 — несколько значений одного поля:
Актуально для: checkbox-групп;
Пример 3 — добавление и изменение данных:
Пример 4 — работа с файлами:
Файл передаётся как File (подтип
Пример 5 — отправка через
Не нужно вручную задавать Content-Type, браузер автоматически установит
Пример 6 — перебор всех данных:
🔥
📣 JS Ready | #практика
FormData — базовый Web API для сбора и отправки данных HTML-форм. Позволяет работать с текстовыми полями и файлами без ручной сериализации и напрямую передаётся в fetch или XMLHttpRequest.Создание
FormData из формы:const form = document.querySelector('form');
const formData = new FormData(form);В
FormData попадают только successful controls: элементы с name и без disabled, checked checkbox/radio, выбранные файлы и submit-кнопка при реальном submit; без name — не попадают.Пример 1 — чтение значений:
formData.get('email');
formData.get('password');get() возвращает первое значение по ключу. Для полей с несколькими значениями используется getAll().Пример 2 — несколько значений одного поля:
formData.getAll('tags');Актуально для: checkbox-групп;
<select multiple>; динамических списков (повторяющиеся ключи).Пример 3 — добавление и изменение данных:
formData.set('role', 'admin');
formData.append('token', 'abc123');set() удаляет все предыдущие значения по ключу и устанавливает новое; append() добавляет ещё одно значение (важно для повторяющихся ключей и файлов)Пример 4 — работа с файлами:
const fileInput = document.querySelector('input[type="file"]');
if (fileInput.files.length > 0) {
formData.append('avatar', fileInput.files[0]);
}Файл передаётся как File (подтип
Blob) с именем, MIME-типом и размером. При выборе нескольких файлов (multiple) FormData содержит несколько записей с одинаковым ключом.Пример 5 — отправка через
fetchfetch('/api/profile', {
method: 'POST',
body: formData
});Не нужно вручную задавать Content-Type, браузер автоматически установит
multipart/form-data с корректным boundary.Пример 6 — перебор всех данных:
for (const [key, value] of formData.entries()) {
console.log(key, value);
}FormData — стандартный и часто незаменимый инструмент для веб-приложений с формами, файлами и реальными пользовательскими данными.Please open Telegram to view this post
VIEW IN TELEGRAM
👍12❤9🤝8🔥1
Например,
charAt() возвращает символ по индексу, includes() проверяет наличие подстроки, а slice() извлекает часть строки без изменения оригинала.На картинке — часто используемые методы для работы со строками: поиск, сравнение, замена, разбиение, изменение регистра и форматирование.
Сохрани, чтобы не забыть!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥20👍12🤝8
NodeList — это не массив, но его легко им сделать!
Spread-оператор делает то же самое короче и читаемее:
После этого можно использовать весь арсенал массивов без ограничений:
🔥 Это один из самых частых реальных кейсов в DOM-коде, особенно при обработке списков, таблиц и UI-компонентов. Превращает псевдомассив в полноценный массив.
📣 JS Ready | #совет
querySelectorAll возвращает NodeList, у которого нет map, filter и других методов массива. Раньше приходилось писать через Array.from:const items = Array.from(document.querySelectorAll('.item'));Spread-оператор делает то же самое короче и читаемее:
const items = [...document.querySelectorAll('.item')];После этого можно использовать весь арсенал массивов без ограничений:
const visible = items.filter(el => el.offsetParent !== null);
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17❤7🔥5🤝3
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14🔥10❤9
Дедупликация массива объектов по ключу!
При работе с API, кэшем, пагинацией или объединении данных дубликаты появляются постоянно. Почти всегда нужно оставить только один объект для каждого уникального значения поля (чаще всего id).
Допустим, есть массив пользователей:
Задача: оставить только по одному объекту для каждого id.
По сути мы строим индекс: если ключ встретился впервые — сохраняем объект, если повторно — игнорируем. В результате остаются первые версии элементов:
Такой вариант особенно полезен, когда порядок данных важен и нужно сохранить именно первый пришедший объект.
Если важен последний дубликат (например, пришло обновление), достаточно перезаписывать значение в Map — сохранится последняя версия объекта:
Теперь при повторном ключе старый объект заменяется новым, и в итоге остаются последние версии:
Это часто используется при мердже страниц пагинации или обновлений из веб-сокета.
Если уникальность задаётся не полем, а вычислением (например, комбинацией значений), можно передать функцию получения ключа:
Например, можно убрать дубликаты по имени без учёта регистра:
🔥 Небольшой нюанс: если у части объектов нет нужного поля, они получат ключ undefined и схлопнутся в один элемент. Иногда это ожидаемо, иногда — источник багов, поэтому стоит учитывать.
📣 JS Ready | #практика
При работе с API, кэшем, пагинацией или объединении данных дубликаты появляются постоянно. Почти всегда нужно оставить только один объект для каждого уникального значения поля (чаще всего id).
Допустим, есть массив пользователей:
const users = [
{ id: 1, name: "Alex" },
{ id: 2, name: "Maria" },
{ id: 1, name: "Alex (duplicate)" },
{ id: 3, name: "John" },
{ id: 2, name: "Maria (duplicate)" }
];
Задача: оставить только по одному объекту для каждого id.
Map удобен для дедупа: ключи не кастуются к строке, доступ работает за O(1), весь алгоритм — один проход O(n), а реализация остаётся простой и читаемой:const uniqueBy = (items, key) => {
const map = new Map();
for (const item of items) {
const k = item[key];
if (!map.has(k)) map.set(k, item);
}
return [...map.values()];
};По сути мы строим индекс: если ключ встретился впервые — сохраняем объект, если повторно — игнорируем. В результате остаются первые версии элементов:
uniqueBy(users, "id");
/*
[
{ id: 1, name: "Alex" },
{ id: 2, name: "Maria" },
{ id: 3, name: "John" }
]
*/
Такой вариант особенно полезен, когда порядок данных важен и нужно сохранить именно первый пришедший объект.
Если важен последний дубликат (например, пришло обновление), достаточно перезаписывать значение в Map — сохранится последняя версия объекта:
const uniqueByLast = (items, key) => {
const map = new Map();
for (const item of items) map.set(item[key], item);
return [...map.values()];
};Теперь при повторном ключе старый объект заменяется новым, и в итоге остаются последние версии:
uniqueByLast(users, "id");
/*
[
{ id: 1, name: "Alex (duplicate)" },
{ id: 2, name: "Maria (duplicate)" },
{ id: 3, name: "John" }
]
*/
Это часто используется при мердже страниц пагинации или обновлений из веб-сокета.
Если уникальность задаётся не полем, а вычислением (например, комбинацией значений), можно передать функцию получения ключа:
const uniqueByFn = (items, getKey) => {
const map = new Map();
for (const item of items) {
const k = getKey(item);
if (!map.has(k)) map.set(k, item);
}
return [...map.values()];
};Например, можно убрать дубликаты по имени без учёта регистра:
uniqueByFn(users, u => u.name.toLowerCase());
Please open Telegram to view this post
VIEW IN TELEGRAM
❤10👍9🔥8
🤝15🔥12👍10😁1
Деструктуризация параметров в Callback!
Когда в колбэк приходит объект, не обязательно сначала принимать его целиком, а потом вытаскивать поля:
Можно сразу распаковать нужные свойства в параметрах функции:
Это делает код короче и сразу показывает, какие данные используются внутри колбэка.
🔥 Особенно полезно в
📣 JS Ready | #совет
Когда в колбэк приходит объект, не обязательно сначала принимать его целиком, а потом вытаскивать поля:
users.forEach(user => {
console.log(user.id, user.name);
});Можно сразу распаковать нужные свойства в параметрах функции:
users.forEach(({ id, name }) => {
console.log(id, name);
});Это делает код короче и сразу показывает, какие данные используются внутри колбэка.
map, filter, reduce, обработчиках событий и работе с API-данными.Please open Telegram to view this post
VIEW IN TELEGRAM
👍20❤9🔥8🤝2👎1
This media is not supported in your browser
VIEW IN TELEGRAM
Репозиторий содержит набор заданий и учебный проект по работе с JavaScript, интерфейсами и браузерным API. Здесь последовательная практика: манипуляции с DOM, события, формы, работа с данными и построение интерактивных элементов. Отличный вариант, если хочешь попрактиковаться.
Оставляю ссылочку: GitHub📱
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥18👍9🤝8
Делаем undo / redo для состояния через стек!
Отмена и повтор действий — частый интерактивный сценарий: формы, редакторы, фильтры, админки. Реализуется через два стека:
Создаём простое состояние и кнопку изменения:
Добавляем элементы на страницу, чтобы можно было взаимодействовать с интерфейсом и видеть результат изменений:
Создаём состояние приложения — в примере это простой счётчик — и сразу отображаем его текущее значение:
Добавляем историю состояний. Будем хранить прошлые состояния в
Функция изменения состояния. Перед каждым обновлением сохраняем текущий
Изменение состояния по кнопке — просто увеличиваем счётчик на единицу:
Undo — возвращает предыдущее состояние. Текущее состояние при этом переносится в
Redo — восстанавливает состояние из стека
Основные моменты:
🔥 В итоге получаем полноценный undo/redo-механизм на чистом JavaScript без сторонних библиотек.
📣 JS Ready | #практика
Отмена и повтор действий — частый интерактивный сценарий: формы, редакторы, фильтры, админки. Реализуется через два стека:
past и future.Создаём простое состояние и кнопку изменения:
const output = document.createElement("div");
const btn = document.createElement("button");
btn.textContent = "Изменить";Добавляем элементы на страницу, чтобы можно было взаимодействовать с интерфейсом и видеть результат изменений:
document.body.append(btn, output);
Создаём состояние приложения — в примере это простой счётчик — и сразу отображаем его текущее значение:
let state = { count: 0 };
output.textContent = state.count;Добавляем историю состояний. Будем хранить прошлые состояния в
past, а состояния для возможного повтора — в future.const past = [];
const future = [];
Функция изменения состояния. Перед каждым обновлением сохраняем текущий
state в историю, затем применяем новое значение и очищаем redo-историю, потому что она больше не актуальна:function setState(next) {
past.push(structuredClone(state));
state = structuredClone(next); // чтобы избежать мутаций по ссылке
future.length = 0;
output.textContent = state.count;
}Изменение состояния по кнопке — просто увеличиваем счётчик на единицу:
btn.addEventListener("click", () => {
setState({ count: state.count + 1 });
});Undo — возвращает предыдущее состояние. Текущее состояние при этом переносится в
future, чтобы его можно было восстановить обратно:function undo() {
if (!past.length) return;
future.push(structuredClone(state));
state = past.pop();
output.textContent = state.count;
}Redo — восстанавливает состояние из стека
future и делает его текущим:function redo() {
if (!future.length) return;
past.push(structuredClone(state));
state = future.pop();
output.textContent = state.count;
}Основные моменты:
past хранит прошлые состояния, future очищается при новом изменении, structuredClone делает глубокую копию без общих ссылок, подход масштабируется (diff, лимит истории, отдельный менеджер).Please open Telegram to view this post
VIEW IN TELEGRAM
❤12👍8🤝8
Например, startsWith(), endsWith() и includes() используются для логических проверок содержимого строки, а indexOf() и lastIndexOf() — для получения позиции первого и последнего вхождения подстроки.
На изображении собраны базовые методы строкового поиска, которые покрывают большинство повседневных задач при работе с текстом и данными.
Сохраните, чтобы не забыть!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🔥10❤7🤝2