JavaScript Ready | Программирование
8.17K subscribers
832 photos
48 videos
370 links
Авторский канал по разработке на JavaScript.
Ресурсы, обучения, задачи, шпаргалки.
Ежедневно информация пополняется!

Автор: @energy_it

Реклама на бирже:
https://telega.in/c/javascript_readyy
Download Telegram
📂 Шпаргалка по методам поиска в строках!

Например, startsWith(), endsWith() и includes() используются для логических проверок содержимого строки, а indexOf() и lastIndexOf() — для получения позиции первого и последнего вхождения подстроки.

На изображении собраны базовые методы строкового поиска, которые покрывают большинство повседневных задач при работе с текстом и данными.

Сохраните, чтобы не забыть!

📣 JS Ready | #ресурс
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🔥107🤝2
Значение по умолчанию при деструктуризации!

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

Без дефолтов придётся страховаться вручную:
function printUser(user) {
const name = user.name || "Unknown";
const age = user.age || 0;

console.log(name, age);
}


Проблема в том, что оператор || подменяет любые falsy-значения — пустую строку, 0 или false, даже если они валидны.

Корректнее задать значения по умолчанию прямо в параметрах функции. Они применяются только если свойство равно undefined:
function printUser({ name = "Unknown", age = 0 }) {
console.log(name, age);
}


Теперь передача неполных данных не ломает логику:
printUser({ name: "Alex" }); // Alex 0
printUser({ age: 25 }); // Unknown 25
printUser({}); // Unknown 0


Частый кейс — безопасная обработка параметров опционального объекта. Чтобы функция не падала при вызове без аргументов, задаём дефолт всему параметру:
function createUser({ name = "Guest", role = "user" } = {}) {
return { name, role };
}


Теперь корректны все варианты вызова:
createUser({ name: "Mira" });
createUser({});
createUser();


Подход делает сигнатуру функции самодокументируемой и избавляет от защитного кода внутри тела.

🔥 Особенно полезно в API-обёртках, утилитах, React-компонентах и обработчиках конфигурации.

📣 JS Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
👍189🤝8
This media is not supported in your browser
VIEW IN TELEGRAM
👩‍💻 Не хочется каждый раз писать базовую структуру вручную?

Simple React Snippets — добавляет быстрые шаблоны для React: функциональные компоненты, импорт React, хуки, export по умолчанию и другие часто используемые конструкции. Вводишь короткое сокращение, получаешь готовый каркас компонента.

📣 JS Ready | #vscode
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥20👍149👎1
Сглаживание массивов без reduce и рекурсии!

Когда массив содержит вложенные массивы, можно не писать сложные циклы или рекурсивные функции — flat делает это проще:
nested.flat(2); // сглаживает на глубину 2


Если нужно полностью полностью развернуть вложенную структуру любой глубины, можно указать Infinity:
nested.flat(Infinity);


Когда требуется не просто сгладить, а сначала преобразовать элементы, используйте flatMap — он объединяет map и flat(1) в одну операцию:
[1, 2, 3].flatMap(x => [x, x * 2]);


🔥 Такой примем пригодится для обработки результатов API, древовидных структур, списков и любых вложенных данных.

📣 JS Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1411👍10
This media is not supported in your browser
VIEW IN TELEGRAM
☕️ Teamtreehouse — базовый курс по основам языка JS!

Структурированная программа обучения, охватывающая ключевые концепции языка: синтаксис, условные конструкции, функции и основы отладки. Материал подаётся через видеоуроки и задания, что позволяет закреплять теорию на практике и формировать базу для дальнейшего изучения веб-разработки.

📌 Оставляю ссылочку: teamtreehouse.com

📣 JS Ready | #сайт
Please open Telegram to view this post
VIEW IN TELEGRAM
13👍10🔥9🤝1
📱 Числа: преобразование, проверки и парсинг!

В шпаргалке собраны основные способы работы с числовыми значениями. Рассматриваются явное приведение типов, строгие проверки корректности и конечности чисел, а также разбор строковых представлений целых и дробных значений. Материал охватывает примеры валидации, безопасной работы с целыми числами и корректного извлечения чисел из строк.

📣 JS Ready | #шпора
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1410🔥10
Как убрать undefined / null поля из объекта?

Частая проблема, в объекте есть пустые поля, которые ломают API-запросы, формы или сериализацию.

Получаем пары ключ-значение:
Object.entries(obj)


Фильтруем только реальные значения, убирая null и undefined:
.filter(([, v]) => v != null)


Собираем обратно в объект:
Object.fromEntries(...)


🔥 Идеально перед fetch, сохранением настроек, формами и любыми динамическими параметрами, очищает данные без циклов и мутаций.

📣 JS Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
👍159🤝9
📱 Напоминалка по работе с массивами!

Например методы map(), filter(), find() и другие — это быстрый способ трансформировать, искать и фильтровать данные в массивах.

На картинке — 7 ключевых методов массивов.

Сохрани, чтобы не забыть!

📣 JS Ready | #ресурс
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2112🤝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");
});


Класс изменится у контейнера, даже если клик был по вложенному элементу.

🔥 Понимание различия особенно важно при делегировании событий и работе с динамическим DOM. Основа надёжной обработки событий без навешивания обработчиков на каждый элемент.

📣 JS Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
13👍9🔥8
This media is not supported in your browser
VIEW IN TELEGRAM
👩‍💻 Нужно быстро понять, когда и как менялся код?

Git History — показывает историю изменений прямо в VS Code: коммиты по файлу, авторов правок, различия между версиями и изменения строк. Можно быстро посмотреть старый код, найти причину бага или понять логику изменений.

📣 JS Ready | #vscode
Please open Telegram to view this post
VIEW IN TELEGRAM
14🔥8🤝8
Event Delegation — один обработчик вместо десятков!

Частая ошибка — навешивать обработчик на каждый элемент списка. Это усложняет код, требует повторных подписок при обновлении 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() и требует осознанного выбора контейнера, чтобы не перехватывать лишние события.

📣 Code Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥108👍7🤝1
This media is not supported in your browser
VIEW IN TELEGRAM
👩‍💻 Удобный просмотр таблиц в формате CSV!

Rainbow CSV раскрашивает столбцы в разные цвета, благодаря чему данные становятся наглядными и легко читаемыми прямо в редакторе. Помогает быстро ориентироваться в таблицах, находить нужные значения и проверять корректность структуры без использования сторонних программ. Особенно полезно при работе с логами и большими наборами данных.

📣 JS Ready | #vscode
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13🔥9🤝7
Таймауты асинхронных операций

Иногда 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 секунды он будет отменён.

📣 JS Ready | #совет
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥86👍6🤝1
This media is not supported in your browser
VIEW IN TELEGRAM
👍 JavaScript Questions — систематизированная база вопросов и разборов по ключевым концепциям!

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

Оставляю ссылочку: GitHub 📱


📣 JS Ready | #репозиторий
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥149👍8
Свой EventEmitter на чистом JS

Такой подход часто используют для модулей, плагинов, логирования, внутренних событий в приложении и вообще везде, где хочется развязать компоненты.

Начнём с каркаса класса:
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 это важно для архитектуры. Он помогает выстроить события внутри приложения без жёстких связей между модулями и делает код заметно чище.

📣 JS Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
12👍6🔥5
📂 Напоминалка по работе с массивами в JavaScript!

Например, map() позволяет преобразовать каждый элемент массива, filter() — отфильтровать данные по условию, а slice() — получить часть массива без изменения исходного.

На картинке — основные методы массивов, которые помогают работать с данными быстрее и писать чистый код.

Сохрани, чтобы не забыть!

📣 JS Ready | #ресурс
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥12👍9🤝72
ResizeObserver — отслеживание изменения размеров элементов!

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 — базовый инструмент для построения адаптивных компонентов, реагирующих на реальные размеры контейнера, а не только на размер окна.

📣 JS Ready | #практика
Please open Telegram to view this post
VIEW IN TELEGRAM
12👍9🤝8