В шпаргалке собраны основные способы работы с числовыми значениями. Рассматриваются явное приведение типов, строгие проверки корректности и конечности чисел, а также разбор строковых представлений целых и дробных значений. Материал охватывает примеры валидации, безопасной работы с целыми числами и корректного извлечения чисел из строк.Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14❤10🔥10
Как убрать undefined / null поля из объекта?
Частая проблема, в объекте есть пустые поля, которые ломают API-запросы, формы или сериализацию.
Получаем пары ключ-значение:
Фильтруем только реальные значения, убирая null и undefined:
Собираем обратно в объект:
🔥 Идеально перед
📣 JS Ready | #совет
Частая проблема, в объекте есть пустые поля, которые ломают API-запросы, формы или сериализацию.
Получаем пары ключ-значение:
Object.entries(obj)
Фильтруем только реальные значения, убирая null и undefined:
.filter(([, v]) => v != null)
Собираем обратно в объект:
Object.fromEntries(...)
fetch, сохранением настроек, формами и любыми динамическими параметрами, очищает данные без циклов и мутаций.Please open Telegram to view this post
VIEW IN TELEGRAM
👍15❤9🤝9
event.target и event.currentTarget — правильная работа с делегированием!В обработчиках событий часто путают два разных элемента: тот, по которому пользователь действительно кликнул, и тот, на котором висит слушатель. В DOM это разные роли, и для них существуют свойства
event.target и event.currentTarget.event.target — источник события (самый глубокий элемент):list.addEventListener("click", e => {
console.log("target:", e.target);
});
Если кликнуть по кнопке внутри списка,
target будет тем узлом, по которому пришёлся клик. Если внутри кнопки есть вложенные элементы, target может оказаться ими, а не самой кнопкой.event.currentTarget — элемент, на котором висит обработчик:list.addEventListener("click", e => {
console.log("currentTarget:", e.currentTarget);
});
Он всегда равен
list, потому что обработчик привязан именно к этому элементу, независимо от места клика внутри него.Практический пример делегирования:
document
.querySelector("#menu")
.addEventListener("click", e => {
if (e.target.matches("button")) {
console.log("Нажата кнопка:", e.target.textContent);
}
});
Если внутри кнопки есть вложенные элементы, условие может не сработать, потому что
target будет не кнопкой.Надёжнее использовать
closest():document
.querySelector("#menu")
.addEventListener("click", e => {
const btn = e.target.closest("button");
if (!btn || !e.currentTarget.contains(btn)) return;
console.log("Нажата кнопка:", btn.textContent);
});
Проверка
contains гарантирует, что найденная кнопка действительно находится внутри текущего контейнера.Когда нужен именно контейнер — используем
currentTarget:container.addEventListener("click", e => {
e.currentTarget.classList.toggle("active");
});
Класс изменится у контейнера, даже если клик был по вложенному элементу.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤13👍9🔥8
Please open Telegram to view this post
VIEW IN TELEGRAM
❤14🔥8🤝8
Event Delegation — один обработчик вместо десятков!
Частая ошибка — навешивать обработчик на каждый элемент списка. Это усложняет код, требует повторных подписок при обновлении DOM и не работает для динамически добавленных элементов. Гораздо надёжнее использовать делегирование событий — один обработчик на общем родителе.
Обработчик на каждый элемент:
Такой подход не масштабируется: новые элементы остаются без обработки, а при повторной инициализации легко получить дубли подписок.
Делегирование через родителя:
События в DOM всплывают вверх по дереву (bubbling), поэтому родитель может перехватить клик. Через
Работает с динамическими элементами:
Новый элемент автоматически обрабатывается существующим обработчиком — дополнительных подписок не требуется.
🔥 Подход не применим к событиям без всплытия (например,
📣 Code Ready | #практика
Частая ошибка — навешивать обработчик на каждый элемент списка. Это усложняет код, требует повторных подписок при обновлении DOM и не работает для динамически добавленных элементов. Гораздо надёжнее использовать делегирование событий — один обработчик на общем родителе.
Обработчик на каждый элемент:
document.querySelectorAll('.list .item button').forEach(btn => {
btn.addEventListener('click', () => {
console.log('Clicked:', btn.dataset.id);
});
});Такой подход не масштабируется: новые элементы остаются без обработки, а при повторной инициализации легко получить дубли подписок.
Делегирование через родителя:
const list = document.querySelector('.list');
list.addEventListener('click', (e) => {
const button = e.target.closest('button');
if (!button || !list.contains(button)) return;
console.log('Clicked:', button.dataset.id);
});События в DOM всплывают вверх по дереву (bubbling), поэтому родитель может перехватить клик. Через
closest() мы определяем фактический источник действия, даже если клик был по вложенному элементу внутри кнопки.Работает с динамическими элементами:
list.insertAdjacentHTML('beforeend', `
<li class="item">
<button data-id="10">New item</button>
</li>
`);Новый элемент автоматически обрабатывается существующим обработчиком — дополнительных подписок не требуется.
focus, blur), может конфликтовать с точечным использованием stopPropagation() и требует осознанного выбора контейнера, чтобы не перехватывать лишние события.Please open Telegram to view this post
VIEW IN TELEGRAM
🔥10❤8👍7🤝1
This media is not supported in your browser
VIEW IN TELEGRAM
Rainbow CSV раскрашивает столбцы в разные цвета, благодаря чему данные становятся наглядными и легко читаемыми прямо в редакторе. Помогает быстро ориентироваться в таблицах, находить нужные значения и проверять корректность структуры без использования сторонних программ. Особенно полезно при работе с логами и большими наборами данных.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13🔥9🤝7
Таймауты асинхронных операций
Иногда fetch() или любая async-операция может зависнуть. Решение ставить таймаут и прерывать выполнение.
Создаём AbortController:
Ставим таймаут на отмену:
Делаем запрос с signal:
Очищаем таймер после ответа:
Теперь запрос не повиснет навсегда, через 3 секунды он будет отменён.
📣 JS Ready | #совет
Иногда fetch() или любая async-операция может зависнуть. Решение ставить таймаут и прерывать выполнение.
Создаём AbortController:
const controller = new AbortController();
Ставим таймаут на отмену:
const timer = setTimeout(() => controller.abort(), 3000);
Делаем запрос с signal:
const res = await fetch(url, { signal: controller.signal });Очищаем таймер после ответа:
clearTimeout(timer);
Теперь запрос не повиснет навсегда, через 3 секунды он будет отменён.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8❤6👍6🤝1
This media is not supported in your browser
VIEW IN TELEGRAM
Репозиторий представляет собой сборник вопросов с объяснениями: области видимости, замыкания, прототипное наследование, типы данных и особенности работы движка. Материал особенно полезен для подготовки к собеседованиям, повторения базовых принципов и укрепления фундаментальных знаний для разработки.
Оставляю ссылочку: GitHub📱
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥14❤9👍8
Свой EventEmitter на чистом JS
Такой подход часто используют для модулей, плагинов, логирования, внутренних событий в приложении и вообще везде, где хочется развязать компоненты.
Начнём с каркаса класса:
Map хранит пары: имя события -> множество обработчиков.
Set удобен тем, что не допускает дубликатов и быстро удаляет функции.
Теперь метод подписки on.
Сначала достаём список обработчиков для события (или создаём новый):
Теперь добавляем обработчик:
return this чтобы можно было делать цепочки вызовов.
Добавим emit запуск события.
Сначала берём подписчиков:
Если никто не подписан просто выходим.
Вызываем всех обработчиков:
args позволяет передавать любые данные в обработчики.
Теперь off отписка.
Берём подписчиков:
Удаляем конкретный обработчик:
Если после удаления список пустой убираем событие полностью, чтобы не захламлять память.
Создаём обёртку, которая сама себя снимет:
И подписываем:
Итог: свой EventEmitter это важно для архитектуры. Он помогает выстроить события внутри приложения без жёстких связей между модулями и делает код заметно чище.
📣 JS Ready | #практика
Такой подход часто используют для модулей, плагинов, логирования, внутренних событий в приложении и вообще везде, где хочется развязать компоненты.
Начнём с каркаса класса:
class Emitter {
constructor() {
this.events = new Map();
}
}Map хранит пары: имя события -> множество обработчиков.
Set удобен тем, что не допускает дубликатов и быстро удаляет функции.
Теперь метод подписки on.
Сначала достаём список обработчиков для события (или создаём новый):
on(event, handler) {
if (!this.events.has(event)) {
this.events.set(event, new Set());
}
}Теперь добавляем обработчик:
this.events.get(event).add(handler);
return this;
}
return this чтобы можно было делать цепочки вызовов.
Добавим emit запуск события.
Сначала берём подписчиков:
emit(event, ...args) {
const handlers = this.events.get(event);
if (!handlers) return false;
}Если никто не подписан просто выходим.
Вызываем всех обработчиков:
for (const handler of handlers) {
handler(...args);
}
return true;
}args позволяет передавать любые данные в обработчики.
Теперь off отписка.
Берём подписчиков:
off(event, handler) {
const handlers = this.events.get(event);
if (!handlers) return this;
}Удаляем конкретный обработчик:
handlers.delete(handler);
if (handlers.size === 0) this.events.delete(event);
return this;
}
Если после удаления список пустой убираем событие полностью, чтобы не захламлять память.
Создаём обёртку, которая сама себя снимет:
once(event, handler) {
const wrap = (...args) => {
this.off(event, wrap);
handler(...args);
};И подписываем:
this.on(event, wrap);
return this;
}
Итог: свой EventEmitter это важно для архитектуры. Он помогает выстроить события внутри приложения без жёстких связей между модулями и делает код заметно чище.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤12👍6🔥5
Например, map() позволяет преобразовать каждый элемент массива, filter() — отфильтровать данные по условию, а slice() — получить часть массива без изменения исходного.
На картинке — основные методы массивов, которые помогают работать с данными быстрее и писать чистый код.
Сохрани, чтобы не забыть!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥12👍9🤝7❤2
ResizeObserver — отслеживание изменения размеров элементов!
Особенно полезен для адаптивных компонентов, canvas, виртуализации и сложных UI, где размер элемента меняется независимо от окна.
Создаём наблюдатель:
Колбэк вызывается после пересчёта
Если внутри колбэка менять размеры наблюдаемого элемента, можно получить предупреждение: ResizeObserver loop limit exceeded или ResizeObserver loop completed with undelivered notifications. Это защита от бесконечных циклов перерасчёта.
Пример 1 — отслеживание размера элемента:
Для более точных измерений лучше использовать
Пример 2 — адаптация UI под ширину контейнера:
Подходит для container-based адаптивности, когда поведение зависит от размера контейнера, а не viewport. (Для чисто стилевых задач также можно использовать CSS Container Queries.)
Пример 3 — работа с несколькими элементами:
Один
Пример 4 — точные размеры через
Пример 5 — прекращение наблюдения:
Важно отключать наблюдение для удалённых элементов, чтобы избежать лишних ссылок и потенциальных утечек памяти.
🔥
📣 JS Ready | #практика
ResizeObserver — нативный Web API для отслеживания изменения размеров DOM-элементов. Позволяет реагировать на пересчёт layout без window.resize, опроса размеров и сторонних библиотек.Особенно полезен для адаптивных компонентов, canvas, виртуализации и сложных UI, где размер элемента меняется независимо от окна.
Создаём наблюдатель:
const observer = new ResizeObserver(entries => {
entries.forEach(entry => {
console.log(entry.contentRect.width, entry.contentRect.height);
});
});Колбэк вызывается после пересчёта
layout в отдельной фазе доставки уведомлений (обычно до этапа отрисовки). Уведомления могут батчиться браузером.Если внутри колбэка менять размеры наблюдаемого элемента, можно получить предупреждение: ResizeObserver loop limit exceeded или ResizeObserver loop completed with undelivered notifications. Это защита от бесконечных циклов перерасчёта.
Пример 1 — отслеживание размера элемента:
const box = document.querySelector('.box');
observer.observe(box);entry.contentRect содержит размеры content box — области содержимого без padding, border и margin.Для более точных измерений лучше использовать
contentBoxSize или borderBoxSize.Пример 2 — адаптация UI под ширину контейнера:
const container = document.querySelector('.container');
const responsiveObserver = new ResizeObserver(entries => {
const { width } = entries[0].contentRect;
if (width < 500) {
container.classList.add('compact');
} else {
container.classList.remove('compact');
}
});
responsiveObserver.observe(container);Подходит для container-based адаптивности, когда поведение зависит от размера контейнера, а не viewport. (Для чисто стилевых задач также можно использовать CSS Container Queries.)
Пример 3 — работа с несколькими элементами:
document.querySelectorAll('.widget')
.forEach(el => observer.observe(el));Один
ResizeObserver может отслеживать любое количество элементов — браузер оптимизирует доставку уведомлений.Пример 4 — точные размеры через
borderBoxSize:const preciseObserver = new ResizeObserver(entries => {
for (const entry of entries) {
const size = Array.isArray(entry.borderBoxSize)
? entry.borderBoxSize[0]
: entry.borderBoxSize;
console.log(size.inlineSize, size.blockSize);
}
});borderBoxSize учитывает padding и border (аналог box-модели border-box). В современных браузерах поддержка хорошая, но исторически API различался, поэтому часто делают фоллбек на contentRect.Пример 5 — прекращение наблюдения:
observer.unobserve(box); // перестать следить за конкретным элементом
observer.disconnect(); // отключить наблюдатель полностью
Важно отключать наблюдение для удалённых элементов, чтобы избежать лишних ссылок и потенциальных утечек памяти.
ResizeObserver — базовый инструмент для построения адаптивных компонентов, реагирующих на реальные размеры контейнера, а не только на размер окна.Please open Telegram to view this post
VIEW IN TELEGRAM
❤12👍9🤝8
This media is not supported in your browser
VIEW IN TELEGRAM
Это репозиторий с компактным, но очень полезным материалом. Внутри собраны ключевые концепции и паттерны, которые постоянно встречаются в коде. Всё сопровождается небольшими примерами и пояснениями, поэтому ресурс удобно использовать как быстрый справочник, когда нужно освежить синтаксис.
Оставляю ссылочку: GitHub📱
Please open Telegram to view this post
VIEW IN TELEGRAM
❤12👍9🔥8🤝3
Объединение и клонирование объектов!
Иногда нужно объединить несколько объектов или создать копию объекта. Многие делают это вручную, добавляя свойства по одному:
В JS для этого есть нативный метод
Если передать несколько источников, все их свойства будут объединены:
Первый аргумент — объект, в который происходит копирование.
Часто передают пустой
Теперь
🔥 Этот метод особенно полезен при работе с конфигурациями, состоянием приложений, объединением данных API и созданием копий объектов без ручного копирования.
📣 JS Ready | #совет
Иногда нужно объединить несколько объектов или создать копию объекта. Многие делают это вручную, добавляя свойства по одному:
const result = {};
result.id = user.id;
result.name = details.name;В JS для этого есть нативный метод
Object.assign(), который копирует собственные перечисляемые свойства из одного или нескольких объектов в целевой объект:Object.assign(target, ...sources)
Если передать несколько источников, все их свойства будут объединены:
const merged = Object.assign({}, user, details);Первый аргумент — объект, в который происходит копирование.
Часто передают пустой
{}, чтобы получить новый объект и не изменять исходные данные:const clone = Object.assign({}, user);Теперь
clone — поверхностная (shallow) копия объекта.Please open Telegram to view this post
VIEW IN TELEGRAM
👍12❤8🔥7🤝2
This media is not supported in your browser
VIEW IN TELEGRAM
Markdown All in One расширяет возможности работы с Markdown в VS Code: автодополнение, быстрые команды форматирования, создание оглавления, предпросмотр, горячие клавиши и удобная навигация по документу. Всё, что нужно для комфортной работы с документацией и заметками.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14🔥9❤7🤝1
parseInt и map — скрытая ловушка из-за второго аргумента!
Конструкция
Метод
Что происходит на самом деле:
То есть результат начинает зависеть от индекса элемента. Это может привести к ошибкам при обработке данных из API, CSV, query-параметров и любых строковых чисел.
Правильный вариант — явно задать функцию преобразования:
Или использовать
Разница между
Если нужны корректные дробные значения — лучше
Ещё один компактный вариант — унарный плюс:
Он выполняет то же преобразование, что и
🔥 Не передавайте
📣 JS Ready | #практика
Конструкция
array.map(parseInt) выглядит логично, но часто даёт неожиданный результат. Всё из-за сигнатуры функции parseInt(string, radix).Метод
map передаёт в колбэк три аргумента: (element, index, array). Второй аргумент индекс — попадает в parseInt как основание системы счисления (radix).["10", "10", "10"].map(parseInt);
// [10, NaN, 2]
Что происходит на самом деле:
parseInt("10", 0); // 10 (основание определяется автоматически)
parseInt("10", 1); // NaN (radix < 2 — недопустимо)
parseInt("10", 2); // 2 (двоичная система)То есть результат начинает зависеть от индекса элемента. Это может привести к ошибкам при обработке данных из API, CSV, query-параметров и любых строковых чисел.
Правильный вариант — явно задать функцию преобразования:
["10", "10", "10"].map(x => parseInt(x, 10));
// [10, 10, 10]
Или использовать
Number, если нужно преобразовать строку целиком:["10", "10", "10"].map(Number);
// [10, 10, 10]
Разница между
Number и parseInt существенная:Number("10px"); // NaN
parseInt("10px"); // 10parseInt читает число до первого нечислового символа и отбрасывает дробную часть:parseInt("1.5"); // 1Если нужны корректные дробные значения — лучше
Number или parseFloat:["1.5", "2.7"].map(Number);
// [1.5, 2.7]
Ещё один компактный вариант — унарный плюс:
["10", "20", "30"].map(x => +x);
// [10, 20, 30]
Он выполняет то же преобразование, что и
Number, но короче.parseInt напрямую в map. Всегда указывайте radix или используйте Number — так вы избежите неочевидных багов.Please open Telegram to view this post
VIEW IN TELEGRAM
❤13🔥10👍7🤝1
Нативная группировка данных в JS!
Частая задача — сгруппировать данные по какому-то полю. Обычно это делают через
Но в современном JS есть нативный способ группировки —
Метод принимает итерируемую коллекцию и функцию, которая возвращает ключ группы:
Результат — объект, где ключи это группы, а значения — массивы элементов:
Ключи в
Если нужны ключи любого типа без преобразования — можно использовать
🔥 Это упрощает агрегацию данных: аналитика, таблицы, API-ответы, группировка логов, отчёты и подготовку данных для UI.
📣 JS Ready | #совет
Частая задача — сгруппировать данные по какому-то полю. Обычно это делают через
reduce:const byId = users.reduce((acc, u) => {
(acc[u.id] ??= []).push(u);
return acc;
}, {});Но в современном JS есть нативный способ группировки —
Object.groupBy():Object.groupBy(iterable, callback)
Метод принимает итерируемую коллекцию и функцию, которая возвращает ключ группы:
const byId = Object.groupBy(users, u => u.id);
Результат — объект, где ключи это группы, а значения — массивы элементов:
{
"1": [{ id: 1, name: 'Jane' }],
"2": [{ id: 2, name: 'John' }]
}Ключи в
Object.groupBy() становятся свойствами объекта.Если нужны ключи любого типа без преобразования — можно использовать
Map.groupBy():const grouped = Map.groupBy(users, u => u.id);
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥16❤9👍9
This media is not supported in your browser
VIEW IN TELEGRAM
От сортировок, поиска и рекурсии до графов, динамического программирования и даже криптографии - всё собрано в одном месте. Каждый алгоритм снабжён кодом и пояснениями, так что учиться и разбираться просто и интересно.
Оставляю ссылочку: GitHub📱
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥14❤8👍8👎1
Шпаргалка по базовым операциям с регулярными выражениями. Показано, как проверять наличие совпадений, извлекать найденные фрагменты и группы захвата, получать все совпадения в строке, а также выполнять поиск, замену и разделение строк по шаблону. Также кратко разобраны различия в поведении методов и влияние флагов регулярных выражений.Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
1🔥14🤝8👍7❤3