Красивый диапазон дат без ручной склейки!
Очень частая задача в интерфейсе: показать период акции, бронь, событие или дедлайн.
Обычно начинают собирать строку руками:
Но так быстро появляются проблемы с локалями, месяцами и повторяющимися частями даты.
В JS есть нативный метод
Он сам форматирует диапазон по правилам выбранной локали.
Если даты в одном месяце, результат будет компактным.
А если диапазон пересекает месяцы — формат тоже останется корректным.
🔥 Очень полезно для календарей, бронирований, акций, расписаний, событий и любого UI, где нужно показывать диапазоны дат без ручного форматирования.
📣 JS Ready | #совет
Очень частая задача в интерфейсе: показать период акции, бронь, событие или дедлайн.
Обычно начинают собирать строку руками:
`${start} - ${end}`Но так быстро появляются проблемы с локалями, месяцами и повторяющимися частями даты.
В JS есть нативный метод
formatRange() у Intl.DateTimeFormat.fmt.formatRange(startDate, endDate)
Он сам форматирует диапазон по правилам выбранной локали.
fmt.formatRange(
new Date('2026-03-10'),
new Date('2026-03-14')
);
Если даты в одном месяце, результат будет компактным.
// 10–14 марта
А если диапазон пересекает месяцы — формат тоже останется корректным.
fmt.formatRange(
new Date('2026-03-30'),
new Date('2026-04-02')
);
// 30 марта – 2 апреля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17🤝6❤5
Разбираем разницу между Promise.all() и Promise.allSettled()!
Отличия между ними проявляются в момент ошибки. Если использовать
При этом остальные операции не отменяются. Запросы, таймеры и прочая асинхронщина продолжают выполняться. Просто
Когда нужен результат каждой операции независимо от исхода, есть
На выходе получится массив объектов со статусом каждого промиса:
Это удобно для независимых задач. Например, страница загружает профиль пользователя, уведомления и рекомендации. Если рекомендации упали с ошибкой, профиль и уведомления всё равно можно показать. Или пакетная обработка:
После выполнения можно отдельно посмотреть успешные и неуспешные операции, собрать статистику или повторно обработать ошибки.
🔥
📣 JS Ready | #практика
Отличия между ними проявляются в момент ошибки. Если использовать
Promise.all(), то достаточно одного rejected-промиса, чтобы весь результат тоже стал rejected:await Promise.all([
fetchUser(),
fetchPosts(),
fetchComments()
]);
При этом остальные операции не отменяются. Запросы, таймеры и прочая асинхронщина продолжают выполняться. Просто
Promise.all() больше не ждёт общий успешный результат.Когда нужен результат каждой операции независимо от исхода, есть
Promise.allSettled():const results = await Promise.allSettled([
fetchUser(),
fetchPosts(),
fetchComments()
]);
На выходе получится массив объектов со статусом каждого промиса:
[
{ status: "fulfilled", value: {...} },
{ status: "rejected", reason: Error(...) },
{ status: "fulfilled", value: [...] }
]
Это удобно для независимых задач. Например, страница загружает профиль пользователя, уведомления и рекомендации. Если рекомендации упали с ошибкой, профиль и уведомления всё равно можно показать. Или пакетная обработка:
const results = await Promise.allSettled(
users.map(user => sendEmail(user))
);
После выполнения можно отдельно посмотреть успешные и неуспешные операции, собрать статистику или повторно обработать ошибки.
Promise.all() отвечает на вопрос: «Все операции завершились успешно?». Promise.allSettled() отвечает на другой вопрос: «Чем закончилась каждая операция?». Из-за этого они не заменяют друг друга и используются для разных сценариев.Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🔥6❤5
This media is not supported in your browser
VIEW IN TELEGRAM
На сайте собрана большая база материалов для JavaScript-разработчиков: статьи, библиотеки, фреймворки, инструменты, полезные сервисы и обучающие ресурсы. От базовых инструментов до React, Vue, Node.js и др. Отличный ресурс для веб-разработчиков, которые хотят ускорить работу или найти новые инструменты.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10❤6🔥5
При деструктуризации можно задавать значения по умолчанию — они применяются только когда значение свойства равно undefined (включая случай, когда свойства нет в объекте).
На картинке показано, как работает извлечение значений из объекта person, как подставляются fallback-значения при отсутствии данных, а также разбор кейсов с undefined, null и другими типами значений.
Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🔥5🤝3
Сидеть и работать в корпорации — страшно, жизнь-то мимо проходит. Уходить строить бизнес — страшно, а вдруг прогорит. Один из вариантов — разрабатывать свой пет-проект по вечерам. Многие успешные компании, например, Twitter, создавались именно так. Это не значит, что ваш проект обязательно заработает миллиарды, но заработать больше, чем в найме, и получить ценный опыт — вполне реально.
Перед началом разработки появляется множество вопросов, например:
• Как выбрать идею для пет-проекта?
• Что нужно знать про маркетинг
• Как запуститься и довести до первых продаж не имея бюджета на рекламу?
В телеграм-канале «Твой пет проект», Михаил Табунов делится своим опытом с разработчиками и менеджерами.
Он рассказывает, где искать идею для нового проекта, что нужно знать о маркетинге, как запустить стартап и привлечь первых 10 клиентов, а также о многих других важных вещах.
Подписывайтесь на «Твой пет проект», получайте пользу от практиков рынка!
https://t.me/+8Frwa03ciVlhNTky
Перед началом разработки появляется множество вопросов, например:
• Как выбрать идею для пет-проекта?
• Что нужно знать про маркетинг
• Как запуститься и довести до первых продаж не имея бюджета на рекламу?
В телеграм-канале «Твой пет проект», Михаил Табунов делится своим опытом с разработчиками и менеджерами.
Он рассказывает, где искать идею для нового проекта, что нужно знать о маркетинге, как запустить стартап и привлечь первых 10 клиентов, а также о многих других важных вещах.
Подписывайтесь на «Твой пет проект», получайте пользу от практиков рынка!
https://t.me/+8Frwa03ciVlhNTky
Telegram
Твой пет проект
Канал про то, как создать свой маленький свечной заводик
Пишу про:
- Запуски и как сделать первые 10 продаж
- Прожарка идей
- Кейсы роста и ведения проекта параллельно с работой
Автор - Михаил Табунов - @bossofyourboss
Связь @to_baza_education
Пишу про:
- Запуски и как сделать первые 10 продаж
- Прожарка идей
- Кейсы роста и ведения проекта параллельно с работой
Автор - Михаил Табунов - @bossofyourboss
Связь @to_baza_education
❤1
Сохраняем причину ошибки без потери контекста!
При обработке и повторном выбрасывании исключений исходный контекст ошибки может быть утерян, что усложняет диагностику.
Раньше приходилось вручную дописывать сообщение:
Так стек и тип исходной ошибки легко теряются.
В JavaScript есть нативный
Теперь верхняя ошибка объясняет контекст, а
Это удобно, когда ошибка проходит через несколько уровней: чтение файла, парсинг JSON, валидация, инициализация приложения.
🔥
📣 JS Ready | #совет
При обработке и повторном выбрасывании исключений исходный контекст ошибки может быть утерян, что усложняет диагностику.
Раньше приходилось вручную дописывать сообщение:
throw new Error('Config loading failed: ' + err.message);Так стек и тип исходной ошибки легко теряются.
В JavaScript есть нативный
Error.cause.throw new Error('Не удалось загрузить конфиг', { cause: err });Теперь верхняя ошибка объясняет контекст, а
cause хранит настоящую причину.error.cause
Это удобно, когда ошибка проходит через несколько уровней: чтение файла, парсинг JSON, валидация, инициализация приложения.
try {
JSON.parse('{bad json}');
} catch (err) {
throw new Error('Config parse failed', { cause: err });
}Error.cause помогает строить цепочки ошибок без склейки строк, потери stack trace и хаоса в логах.Please open Telegram to view this post
VIEW IN TELEGRAM
🔥12👍7❤4
This media is not supported in your browser
VIEW IN TELEGRAM
На странице собрана крутая подборка из 8 полезных шпаргалок для веб-разработчиков. Здесь справочники по HTML, CSS, Grid Layout, Flexbox, JavaScript, React и Git с примерами кода, схемами и наглядными объяснениями. Полезно для frontend-разработчиков: можно быстро освежить знания по вёрстке, JavaScript и др. инструментам.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥10👍7🤝5❤1
Object.assign и spread: почему не копируются геттеры!
Пока объект состоит только из обычных полей, никакой разницы не видно.
Проблема появляется, когда в объекте есть геттеры.
Когда вызывается
Дальше результат просто записывается в новый объект как обычное поле.
В копии уже нет никакого геттера, там обычное значение, полученное в момент копирования.
В оригинальном объекте всё иначе — там сохраняется сам
Он тоже читает свойства, поэтому геттер вызывается в момент создания нового объекта, а не переносится как структура.
Если нужно сохранить именно поведение объекта вместе с геттерами, используют копирование дескрипторов.
В этом варианте ничего не вычисляется заранее — переносится описание свойств как есть. И
🔥 Итог простой: оба механизма не копируют структуру свойств. Они читают значения, поэтому геттеры срабатывают в момент копирования, а в новый объект попадает уже результат, а не логика свойства.
📣 JS Ready | #практика
Object.assign и spread часто используют как быстрый способ скопировать объект, и на простых структурах всё действительно выглядит как прямое копирование значений.const user = {
name: "Анна"
};
const copy = Object.assign({}, user);
console.log(copy);
Пока объект состоит только из обычных полей, никакой разницы не видно.
Проблема появляется, когда в объекте есть геттеры.
const user = {
firstName: "Анна",
lastName: "Иванова",
get fullName() {
console.log("getter called");
return `${this.firstName} ${this.lastName}`;
}
};
fullName здесь не хранит значение. Это вычисляемое свойство, и оно выполняется в момент чтения.Когда вызывается
Object.assign, он проходит по собственным перечисляемым свойствам и читает каждое через [[Get]]. В этот момент геттер реально срабатывает.const copy = Object.assign({}, user);
Дальше результат просто записывается в новый объект как обычное поле.
console.log(Object.getOwnPropertyDescriptor(copy, "fullName"));
В копии уже нет никакого геттера, там обычное значение, полученное в момент копирования.
{
value: "Анна Иванова",
writable: true,
enumerable: true,
configurable: true
}
В оригинальном объекте всё иначе — там сохраняется сам
accessor, а не результат его выполнения.console.log(Object.getOwnPropertyDescriptor(user, "fullName"));
{
get: [Function],
set: undefined,
enumerable: true,
configurable: true
}
spread работает ровно так же.const copy = {
...user
};
Он тоже читает свойства, поэтому геттер вызывается в момент создания нового объекта, а не переносится как структура.
Если нужно сохранить именно поведение объекта вместе с геттерами, используют копирование дескрипторов.
const copy = Object.defineProperties(
{},
Object.getOwnPropertyDescriptors(user)
);
В этом варианте ничего не вычисляется заранее — переносится описание свойств как есть. И
Object.assign, и spread работают только с собственными перечисляемыми свойствами. Прототипные свойства в процесс не попадают.Please open Telegram to view this post
VIEW IN TELEGRAM
❤9👍7🔥6
Например,
new Date() создаёт объект даты, getFullYear() возвращает текущий год, а toISOString() помогает получить дату в удобном формате для API и хранения данных.На картинке — основные методы Date, которые пригодятся для создания, изменения, форматирования и получения значений даты.
Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13❤5👍5
Слышали о BitGN E-commerce AI Agent Challenge?
ECOM1 - бенчмарк агентной коммерции. AI-агенты работают в симуляции интернет-магазина: корзины, заказы, чекаут и т.д.
Меня зацепил самый умный из быстрых агентов - Exoskeleton от Ильяса Салихова, CTO RetailCRM. Взял 1 место в Speed и топ Live PROD на gpt-5.4-mini (в 6 раз дешевле gpt-5.5 конкурентов).
Секрет в архитектуре:
• Mini - слабое тело, вокруг каркас из кода и nano-моделей. Данные грузятся до старта, nano разбирает намерения: фрод, манипуляция, подмена личности.
• Безопасность зашита в код, решения принимает логика. Ссылки на регламенты собираются сами, финальная nano причёсывает ответ.
• Тяжёлая логика в коде. Модель делает только то, в чём сильна.
Итог: обошла старшие модели по очкам и скорости.
Полная статья со схемами от Ильяса. А ещё у него канал про инженерию и AI - рекомендую подписаться🔗
ECOM1 - бенчмарк агентной коммерции. AI-агенты работают в симуляции интернет-магазина: корзины, заказы, чекаут и т.д.
Меня зацепил самый умный из быстрых агентов - Exoskeleton от Ильяса Салихова, CTO RetailCRM. Взял 1 место в Speed и топ Live PROD на gpt-5.4-mini (в 6 раз дешевле gpt-5.5 конкурентов).
Секрет в архитектуре:
• Mini - слабое тело, вокруг каркас из кода и nano-моделей. Данные грузятся до старта, nano разбирает намерения: фрод, манипуляция, подмена личности.
• Безопасность зашита в код, решения принимает логика. Ссылки на регламенты собираются сами, финальная nano причёсывает ответ.
• Тяжёлая логика в коде. Модель делает только то, в чём сильна.
Итог: обошла старшие модели по очкам и скорости.
Полная статья со схемами от Ильяса. А ещё у него канал про инженерию и AI - рекомендую подписаться🔗
❤1
Генерируем UUID без библиотек!
Очень частая задача: создать уникальный id для пользователя, заказа, файла или любой сущности.
Раньше для этого почти всегда тянули библиотеки типа uuid.
Хотя в современном JavaScript это уже есть нативно.
Метод сразу возвращает криптографически стойкий UUID v4.
Результат выглядит так:
Подходит для случаев, где нужен уникальный идентификатор: id сущностей, ключи записей, request/session id, временные идентификаторы.
Для секретных токенов (reset password, API tokens) лучше использовать
В браузере работает в secure context — HTTPS или localhost.
🔥
📣 JS Ready | #совет
Очень частая задача: создать уникальный id для пользователя, заказа, файла или любой сущности.
Раньше для этого почти всегда тянули библиотеки типа uuid.
import { v4 as uuid } from 'uuid';Хотя в современном JavaScript это уже есть нативно.
crypto.randomUUID()
Метод сразу возвращает криптографически стойкий UUID v4.
const id = crypto.randomUUID();
Результат выглядит так:
36b8f84d-df4e-4d49-b662-bcde71a8764fПодходит для случаев, где нужен уникальный идентификатор: id сущностей, ключи записей, request/session id, временные идентификаторы.
Для секретных токенов (reset password, API tokens) лучше использовать
crypto.getRandomValues() или crypto.randomBytes().В браузере работает в secure context — HTTPS или localhost.
crypto.randomUUID() — простой способ получать уникальные id.Please open Telegram to view this post
VIEW IN TELEGRAM
👍17❤7🤝4🔥2
Надоело долбить LeetCode в пустоту? 🎮
Девстанция — это не очередной список задач. Это RPG для программиста:
🕸 Паутина вместо списка. Каждая задача — узел на графе. Открываешь одни — открываешь путь к другим. Панорамируешь, зумишь, видишь прогресс физически. Skill Tree в мире кодинга.
🏆 Сезоны. 180 дней на прохождение паутины. В конце — нагрды и подведение итогов. Каждый сезон — перерождение. Никто не стартует с форой.
🔥 Геймификация. Стрики, ежедневные челленджи, достижения, рейтинги за сегодня/вчера/неделю/сезон, графики активности — ощути прилив азарта.
👥 Лента событий. Видишь, кто только что решил задачу, кто взял золото дня, кто выбил ачивку. Ты не один в тёмной комнате.
Первый сезон уже идёт. Заходи в паутину 🕸
👉 Решай задачи на dev-station.ru
Девстанция — это не очередной список задач. Это RPG для программиста:
🕸 Паутина вместо списка. Каждая задача — узел на графе. Открываешь одни — открываешь путь к другим. Панорамируешь, зумишь, видишь прогресс физически. Skill Tree в мире кодинга.
🏆 Сезоны. 180 дней на прохождение паутины. В конце — нагрды и подведение итогов. Каждый сезон — перерождение. Никто не стартует с форой.
🔥 Геймификация. Стрики, ежедневные челленджи, достижения, рейтинги за сегодня/вчера/неделю/сезон, графики активности — ощути прилив азарта.
👥 Лента событий. Видишь, кто только что решил задачу, кто взял золото дня, кто выбил ачивку. Ты не один в тёмной комнате.
Первый сезон уже идёт. Заходи в паутину 🕸
👉 Решай задачи на dev-station.ru
🔥3❤1
AbortSignal.timeout() — встроенный способ задавать таймаут для fetch!
У
Долгое время стандартным решением был
Подход полностью рабочий, но даже для базового таймаута требует дополнительной логики: создание контроллера, запуск таймера и последующую очистку.
С появлением
В этом случае
Для типового случая этого обычно достаточно. Обработка ошибок при этом остаётся стандартной.
Если запрос был прерван через
Механизм работает не только с
Отдельно стоит упомянуть
В таком случае операция завершится при срабатывании первого сигнала — либо по ручной отмене, либо по таймауту.
🔥 Если в проекте до сих пор используется ручная реализация таймаута через
📣 JS Ready | #практика
У
fetch нет встроенного параметра для ограничения времени ожидания. Если сервер отвечает слишком долго или соединение зависает, запрос может оставаться активным неопределённое время.Долгое время стандартным решением был
AbortController в сочетании с setTimeout().const controller = new AbortController();
const timeoutId = setTimeout(() => {
controller.abort();
}, 5000);
try {
const response = await fetch("/api/users", {
signal: controller.signal
});
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
} finally {
clearTimeout(timeoutId);
}
Подход полностью рабочий, но даже для базового таймаута требует дополнительной логики: создание контроллера, запуск таймера и последующую очистку.
С появлением
AbortSignal.timeout() эта задача решается значительно проще.const response = await fetch("/api/users", {
signal: AbortSignal.timeout(5000)
});
const data = await response.json();
console.log(data);
В этом случае
AbortSignal автоматически перейдёт в состояние aborted через указанное количество миллисекунд, после чего операция будет отменена.Для типового случая этого обычно достаточно. Обработка ошибок при этом остаётся стандартной.
try {
const response = await fetch("/api/users", {
signal: AbortSignal.timeout(5000)
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return await response.json();
} catch (error) {
if (error.name === "TimeoutError") {
console.log("Время ожидания истекло");
} else {
console.error(error);
}
}
Если запрос был прерван через
AbortSignal.timeout(), ошибка обычно имеет имя TimeoutError. Если отмена произошла вручную через AbortController.abort(), чаще это будет AbortError. Это даёт возможность разделять сценарии таймаута и ручной отмены на уровне обработки ошибок.Механизм работает не только с
fetch. Любой API с поддержкой AbortSignal может использовать тот же подход.await someAsyncOperation({
signal: AbortSignal.timeout(10000)
});
Отдельно стоит упомянуть
AbortSignal.any(), который позволяет объединять несколько сигналов отмены.const controller = new AbortController();
const signal = AbortSignal.any([
controller.signal,
AbortSignal.timeout(5000)
]);
await fetch("/api/users", { signal });
В таком случае операция завершится при срабатывании первого сигнала — либо по ручной отмене, либо по таймауту.
AbortController и setTimeout, сейчас во многих случаях её можно упростить.Please open Telegram to view this post
VIEW IN TELEGRAM
❤13👍6🔥5
This media is not supported in your browser
VIEW IN TELEGRAM
На сайте собрана большая база материалов по веб-разработке: подробные уроки по HTML5, CSS3, JavaScript и jQuery, а также удобные справочники по HTML- и CSS-свойствам. Здесь можно найти разбор тегов, форм, анимаций, Flexbox, Grid, DOM и других ключевых технологий фронтенда. Большое количество практических примеров, готовых решений и UI-эффектов для интерфейсов.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13👍6❤5
Берём первый успешный async-результат!
Иногда есть несколько источников данных: основной API, резервный endpoint или кеш. Нужно взять тот, который первым успешно ответит, а не просто завершится первым.
Для этого есть
Он вернёт первый выполненный
В отличие от
Если упали все варианты, тогда будет
🔥 Полезно для резервных API, CDN-зеркал, запасных адресов сервера, загрузки конфигурации и любой логики, где важен первый успешный результат.
📣 JS Ready | #совет
Иногда есть несколько источников данных: основной API, резервный endpoint или кеш. Нужно взять тот, который первым успешно ответит, а не просто завершится первым.
Для этого есть
Promise.any().Promise.any([main, backup, cache])
Он вернёт первый выполненный
Promise и проигнорирует те, которые упали.const response = await Promise.any([
fetch('/api/main'),
fetch('/api/backup')
]);
В отличие от
Promise.race(), он не падает из-за первого reject.Promise.race([...]) // первый завершился — и всё
Promise.any([...]) // ждёт первый успешный
Если упали все варианты, тогда будет
AggregateError.catch (err) {
console.log(err.errors);
}Please open Telegram to view this post
VIEW IN TELEGRAM
❤16🔥5👍4
Парсим URL без try...catch!
Очень часто нужно проверить, является ли строка корректным URL. Обычно для этого используют конструктор URL, но он выбрасывает исключение.
Из-за этого приходится оборачивать код в
Теперь в JavaScript появился
Если строка содержит корректный URL, метод вернёт объект URL.
Если строка некорректна — вместо исключения вернётся
Это позволяет писать обычные проверки без лишней обработки ошибок.
🔥
📣 JS Ready | #совет
Очень часто нужно проверить, является ли строка корректным URL. Обычно для этого используют конструктор URL, но он выбрасывает исключение.
new URL(input);
Из-за этого приходится оборачивать код в
try...catch.Теперь в JavaScript появился
URL.parse().const url = URL.parse(input);
Если строка содержит корректный URL, метод вернёт объект URL.
console.log(url.hostname);
Если строка некорректна — вместо исключения вернётся
null.URL.parse('not a url');
// nullЭто позволяет писать обычные проверки без лишней обработки ошибок.
URL.parse() — удобный способ валидировать и разбирать URL без try...catch, что особенно полезно при работе с пользовательским вводом, API и роутингом.Please open Telegram to view this post
VIEW IN TELEGRAM
👍12❤7🔥5
Например,
push() добавляет элементы в массив, map() создаёт новый после обработки данных, а filter() помогает отбирать нужные значения.На картинке — 18 практических задач с решениями по работе с массивами JavaScript: создание, изменение, поиск, удаление, сортировка, объединение, преобразование и обработка данных.
Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤10🔥5👍3
delete: почему его осторожно используют в производительном коде!
Например:
Выглядит просто, и в большинстве обычных случаев так и есть. Если вы удалили одно свойство из небольшого объекта — скорее всего, никакой разницы по производительности не заметите.
Но ситуация меняется, когда такие операции начинают выполняться тысячи раз подряд или применяются к большим коллекциям объектов.
JavaScript-движки вроде V8 оптимизируют работу с объектами, которые имеют одинаковую структуру. Когда объекты выглядят одинаково, движку проще хранить информацию о них и быстрее выполнять операции доступа к свойствам.
Например:
Все объекты здесь имеют одинаковую форму: у каждого есть
Но если начать менять структуру объектов:
один объект уже отличается от остальных.
Если сделать это массово:
коллекция становится неоднородной.
Для разработчика это обычное изменение данных, но для JavaScript-движка это уже разные варианты объектов, которые сложнее оптимизировать. Особенно это может быть заметно в местах, где вы постоянно работаете с большими массивами одинаковых объектов.
Например:
Допустим, дальше нужно убрать цену у всех товаров:
Технически код правильный. Но если это горячий участок приложения, где такой цикл выполняется часто и на больших объёмах данных, можно оставить структуру объектов прежней:
Теперь поле остаётся частью объекта:
А после
Разница такая:
Например, когда нужно удалить ключ из кэша:
Здесь объект используется как хранилище ключей, и удаление свойства полностью соответствует задаче.
Если структура данных постоянно меняется, часто используют
Ещё один момент, который часто вызывает вопросы:
Например:
После удаления
🔥 Если вы работаете с большими массивами однотипных объектов, большим количеством данных или производительными участками кода, стоит помнить: частое изменение структуры объектов может влиять на оптимизации JavaScript-движка.
📣 JS Ready | #практика
delete — стандартный оператор JavaScript для удаления свойств объекта. На практике он встречается довольно часто: удалить временное поле, убрать ненужный параметр перед отправкой данных, очистить объект после выполнения операции.Например:
const user = {
name: "Анна",
age: 25,
role: "admin"
};
delete user.age;
console.log(user);
// { name: "Анна", role: "admin" }
Выглядит просто, и в большинстве обычных случаев так и есть. Если вы удалили одно свойство из небольшого объекта — скорее всего, никакой разницы по производительности не заметите.
Но ситуация меняется, когда такие операции начинают выполняться тысячи раз подряд или применяются к большим коллекциям объектов.
JavaScript-движки вроде V8 оптимизируют работу с объектами, которые имеют одинаковую структуру. Когда объекты выглядят одинаково, движку проще хранить информацию о них и быстрее выполнять операции доступа к свойствам.
Например:
const users = [
{
id: 1,
name: "Анна",
age: 25
},
{
id: 2,
name: "Иван",
age: 30
},
{
id: 3,
name: "Олег",
age: 28
}
];
Все объекты здесь имеют одинаковую форму: у каждого есть
id, name и age. Такой подход часто встречается в реальных приложениях: списки пользователей, товары, сообщения, записи из базы данных.Но если начать менять структуру объектов:
delete users[0].age;
один объект уже отличается от остальных.
Если сделать это массово:
delete users[0].age;
delete users[1].age;
delete users[2].age;
коллекция становится неоднородной.
Для разработчика это обычное изменение данных, но для JavaScript-движка это уже разные варианты объектов, которые сложнее оптимизировать. Особенно это может быть заметно в местах, где вы постоянно работаете с большими массивами одинаковых объектов.
Например:
const products = data.map(item => ({
id: item.id,
title: item.title,
price: item.price
}));
Допустим, дальше нужно убрать цену у всех товаров:
for (const product of products) {
delete product.price;
}
Технически код правильный. Но если это горячий участок приложения, где такой цикл выполняется часто и на больших объёмах данных, можно оставить структуру объектов прежней:
for (const product of products) {
product.price = undefined;
}
Теперь поле остаётся частью объекта:
console.log("price" in products[0]);
// true
А после
delete оно полностью исчезает:delete products[0].price;
console.log("price" in products[0]);
// false
Разница такая:
undefined — свойство осталось, изменилось только значение; delete — свойство удалено из объекта полностью. Но из этого не следует, что delete нужно запрещать, есть много случаев, где он является правильным решением.Например, когда нужно удалить ключ из кэша:
const cache = {};
cache.users = data;
delete cache.users;
Здесь объект используется как хранилище ключей, и удаление свойства полностью соответствует задаче.
Если структура данных постоянно меняется, часто используют
Map:const cache = new Map();
cache.set("users", data);
cache.delete("users");
Map хорошо подходит для динамических коллекций: кэшей, словарей, временных хранилищ и таблиц соответствий, где ключи регулярно добавляются и удаляются.Ещё один момент, который часто вызывает вопросы:
delete удаляет только свойство объекта, но не сам объект из памяти.Например:
const user = {
settings: {
theme: "dark"
}
};
const settings = user.settings;
delete user.settings;
console.log(settings.theme);
// dark
После удаления
user.settings объект всё ещё существует, потому что переменная settings продолжает хранить на него ссылку. То есть delete убирает связь между объектом и свойством, но не уничтожает данные, на которые ещё кто-то ссылается.Please open Telegram to view this post
VIEW IN TELEGRAM
👍10❤5🔥5
Клонирование объектов без JSON.stringify!
Очень часто для копии объекта используют старый приём:
Но это подходит только для простых JSON-данных и может неожиданно менять структуру объекта.
В современном JavaScript есть нативный способ —
Он создаёт полноценную глубокую копию, сохраняя типы данных.
После копирования остаются настоящие
Также
🔥
📣 JS Ready | #совет
Очень часто для копии объекта используют старый приём:
const copy = JSON.parse(JSON.stringify(obj));
Но это подходит только для простых JSON-данных и может неожиданно менять структуру объекта.
В современном JavaScript есть нативный способ —
structuredClone():const copy = structuredClone(original);
Он создаёт полноценную глубокую копию, сохраняя типы данных.
const user = {
created: new Date(),
roles: new Set(['admin'])
};
const clone = structuredClone(user);После копирования остаются настоящие
Date и Set, а не преобразованные значения.Также
structuredClone() умеет работать с циклическими ссылками:const obj = {};
obj.self = obj;
const copy = structuredClone(obj);structuredClone() — замена JSON-клонированию для глубоких копий объектов без сторонних библиотек и скрытых потерь данных.Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥7🤝4
В этой статье:
• Простым языком объясняется, что такое API и зачем он нужен в современных приложениях;
• На примере маркетплейса показывается, как программы обмениваются данными между собой;
• Разбирается разница между UI, frontend, backend и API;
• Показывается, как работают endpoint’ы, JSON и HTTP-запросы;🔊 Продолжай читать на Habr!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🔥5🤝3
Шпаргалка по циклам в JavaScript!
Например,
На картинке основные конструкции циклов: классический
Сохрани, чтобы не потерять!
📣 JS Ready | #ресурс
Например,
for подходит для ситуаций, когда заранее известно количество итераций, а for...of является способом перебора значений массивов, строк и других итерируемых объектов.На картинке основные конструкции циклов: классический
for, циклы с предварительной и постусловной проверкой while и do...while, перебор коллекций через for...of и for...in, метод массива forEach(), управление выполнением, а также примеры вложенных циклов.Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10❤6🔥6🤝2