Как легко писать функции с любым количеством аргументов?
Бывает, заранее неизвестно, сколько аргументов придёт в функцию. Некоторые используют
Более современный и правильный способ —
Все аргументы автоматически собираются в массив
Важно не путать
rest — собирает аргументы внутри функции;
spread — разворачивает массив при вызове;
🔥
📣 JS Ready | #совет
Бывает, заранее неизвестно, сколько аргументов придёт в функцию. Некоторые используют
arguments, но у него есть минусы: это не массив, нет методов, и ведёт себя неочевидно.Более современный и правильный способ —
rest parameter (...args):function sum(...args) {
return args.reduce((total, n) => total + n, 0);
}Все аргументы автоматически собираются в массив
args, с ним можно работать как с обычным массивом — map, filter, reduce
sum(1, 2, 3, 4); // 10
Важно не путать
rest и spread:rest — собирает аргументы внутри функции;
spread — разворачивает массив при вызове;
sum(...[1, 2, 3, 4]);
Rest parameter удобен тем, что аргументы сразу ведут себя как массив, без дополнительных шагов.Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13👍9🤝8❤1
Throttle — контроль частоты выполнения!
В браузере есть события, которые срабатывают десятки и сотни раз в секунду:
Базовая реализация
Функция будет вызываться не чаще одного раза за
Важно: это
Использование для
Типичные сценарии: обновление прогресс-бара прокрутки, подсветка текущей секции, вычисление позиций элементов при скролле.
Использование для
🔥 Такой подход особенно важен, когда обработчик содержит вычисления, работу с
📣 JS Ready | #практика
В браузере есть события, которые срабатывают десятки и сотни раз в секунду:
scroll, mousemove, resize. Если выполнять логику на каждый вызов, это быстро приводит к просадкам FPS, дёрганому UI и лишним вычислениям.Throttle позволяет задать верхний предел частоты выполнения обработчика.Базовая реализация
throttle (leading-only):function throttle(fn, delay = 300) {
let last = 0;
return (...args) => {
const now = Date.now();
if (now - last >= delay) {
last = now;
fn(...args);
}
};
}Функция будет вызываться не чаще одного раза за
delay миллисекунд.Важно: это
leading-throttle — вызов происходит в начале интервала, а последнее событие в окне может быть проигнорировано.Использование для
scroll:window.addEventListener(
"scroll",
throttle(() => {
console.log(window.scrollY);
}, 200),
{ passive: true }
);
Типичные сценарии: обновление прогресс-бара прокрутки, подсветка текущей секции, вычисление позиций элементов при скролле.
Использование для
mousemove:window.addEventListener(
"mousemove",
throttle(e => {
console.log(e.clientX);
}, 100)
);
DOM или потенциально тяжёлую логику.Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11❤7🤝7
Большинство багов в UI появляются не из-за рендера или данных, а из-за неявных и конфликтующих состояний.
В этом посте:
• Покажем, как описывать состояния и допустимые переходы;
• Реализуем минимальный движок FSM;
• Применим его к реальному сценарию загрузки данных;
• Отделим состояние от эффектов и упростим логику UI.
FSM позволяет превратить хаотичные условия в строгую модель поведения, где невозможные сценарии просто не могут произойти.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11👍7🤝6❤1
This media is not supported in your browser
VIEW IN TELEGRAM
Здесь собраны различные курсы по JS: от самых основ до уверенной практики. Всё построено просто — читаешь, пишешь код и сразу закрепляешь знания на заданиях. Отличный вариант, если не знаешь с чего начать или хочешь укрепить базу.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🔥10❤8
Фон, реагирующий на звук через Web Audio API
С помощью
Добавим кнопку:
Подключаем микрофон и создаём источник:
Создаём анализатор:
Меняем фон в зависимости от уровня сигнала:
Запускаем:
🔥 Говорите — и фон реагирует в реальном времени. Такой эффект можно использовать в музыкальных визуализациях, интро-анимациях или как интерактивную деталь интерфейса.
📣 JS Ready | #практика
С помощью
Web Audio API можно в реальном времени анализировать входящий аудиопоток с микрофона и использовать полученные данные для динамического изменения фона.Добавим кнопку:
<button id="start">Включить микрофон</button>
Подключаем микрофон и создаём источник:
const btn = document.getElementById("start");
btn.onclick = async () => {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const ctx = new AudioContext();
await ctx.resume(); // требуется в некоторых браузерах
const src = ctx.createMediaStreamSource(stream);Создаём анализатор:
const analyser = ctx.createAnalyser();
const data = new Uint8Array(analyser.frequencyBinCount);
src.connect(analyser);
Меняем фон в зависимости от уровня сигнала:
function animate() {
analyser.getByteFrequencyData(data);
const volume = data.reduce((a, b) => a + b, 0) / data.length;
const hue = Math.min(360, volume * 3);
document.body.style.background = `hsl(${hue}, 80%, 50%)`;
requestAnimationFrame(animate);
}Запускаем:
animate();
btn.remove();
};
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13👍9❤7🤝1
Отмена запросов через AbortController — контроль асинхронности!
При активном взаимодействии с интерфейсом старые запросы могут перезаписывать новые данные. Решение — корректно отменять такие запросы. Для этого в браузере есть нативный
Создаём контроллер, передаём
Базовый пример:
Частый сценарий — каждый новый запрос отменяет предыдущий. Это актуально для поиска, фильтров и автокомплита.
Решение — простая утилита с
Компактная утилита с авто-отменой:
Использование — пример «живого» ввода. Каждый новый ввод автоматически отменяет предыдущий запрос, поэтому в обработку попадают только актуальные данные:
🔥 Такой подход устраняет гонки ответов, упрощает управление асинхронностью и обеспечивает корректное обновление состояния интерфейса.
📣 JS Ready | #практика
При активном взаимодействии с интерфейсом старые запросы могут перезаписывать новые данные. Решение — корректно отменять такие запросы. Для этого в браузере есть нативный
AbortController.Создаём контроллер, передаём
signal в fetch и при необходимости отменяем запрос.Базовый пример:
const controller = new AbortController();
fetch("/api/data", { signal: controller.signal })
.catch(err => {
if (err.name === "AbortError") {
console.log("Запрос отменён");
return;
}
throw err; // остальные ошибки не глушим
});
// где-то позже, когда запрос стал неактуален:
controller.abort();
Частый сценарий — каждый новый запрос отменяет предыдущий. Это актуально для поиска, фильтров и автокомплита.
Решение — простая утилита с
AbortController в замыкании.Компактная утилита с авто-отменой:
function createCancelableFetch() {
let controller;
return (url, init) => {
controller?.abort();
controller = new AbortController();
return fetch(url, { ...init, signal: controller.signal }).then(async r => {
if (!r.ok) {
throw new Error(`HTTP ${r.status}`);
}
return r.json();
});
};
}Использование — пример «живого» ввода. Каждый новый ввод автоматически отменяет предыдущий запрос, поэтому в обработку попадают только актуальные данные:
const fetchUsers = createCancelableFetch();
input.addEventListener("input", e => {
fetchUsers(`/api/users?q=${encodeURIComponent(e.target.value)}`)
.then(console.log)
.catch(err => {
if (err.name === "AbortError") return; // это ожидаемо
console.error(err); // остальные ошибки важны
});
});
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13👍8🤝7❤3
DOM — это то, через что JavaScript управляет HTML: ищет элементы, создаёт новые узлы, вешает события и реагирует на действия пользователя.
На картинке — базовые методы
document и node, а также самые часто используемые события мыши, клавиатуры и форм.Сохрани, чтобы не забыть!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥15👍9🤝8❤1
Быстро приводим значение к boolean — без лишних проверок!
В JS логические значения — это не только
Любое значение в условии считается либо
По умолчанию
Всё остальное —
Если нужно явно получить
Одно
Два
Это часто удобнее и короче, чем
🔥 Поэтому,
📣 JS Ready | #совет
В JS логические значения — это не только
true и false.Любое значение в условии считается либо
truthy, либо falsy.По умолчанию
falsy всего несколько значений:false
0
''
null
undefined
NaN
Всё остальное —
truthy, даже пустые объекты и массивы.Если нужно явно получить
boolean, а не полагаться на неявные приведения, используют оператор логического отрицания.Одно
! инвертирует значение:!0 // true
!1 // false
Два
! подряд делают именно то, что нужно — приводят значение к true или false:!!0 // false
!!1 // true
!!'text' // true
!!null // false
Это часто удобнее и короче, чем
Boolean(value):Boolean(value); // то же самое, но длиннее
!!value — быстрый и наглядный способ получить boolean в коде.Please open Telegram to view this post
VIEW IN TELEGRAM
🔥19👍10❤8
This media is not supported in your browser
VIEW IN TELEGRAM
Сайт с огромной коллекцией задач по программированию, от самых простых до тех, что реально заставят подумать.
Учиться можно на абсолютно любом языке. Отличный способ подтянуть логику, научиться писать аккуратный код и подготовиться к собесам.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13❤7🤝7
Ленивая инициализация логики (Lazy Initialization)!
Иногда логику нужно объявить заранее, но инициализировать только в момент фактического использования. Такой подход снижает нагрузку на старт приложения и позволяет точно контролировать момент инициализации.
Пример обычной инициализации:
Если вызвать функцию при загрузке страницы, инициализация выполнится сразу, независимо от необходимости.
Добавим ленивую обёртку с кэшированием результата:
Функция выполнится только при первом вызове, результат сохранится внутри замыкания и будет переиспользоваться.
Подключение:
Пока
Использование:
Инициализация происходит в этой точке и больше не повторяется.
Пример с DOM (предполагается, что DOM уже доступен):
Элемент создаётся только при первом обращении:
🔥 Подход удобен для логики, которая должна инициализироваться один раз и использоваться по требованию.
📣 JS Ready | #практика
Иногда логику нужно объявить заранее, но инициализировать только в момент фактического использования. Такой подход снижает нагрузку на старт приложения и позволяет точно контролировать момент инициализации.
Пример обычной инициализации:
function initAnalytics() {
console.log("init analytics");
return {
track: e => console.log("track:", e)
};
}Если вызвать функцию при загрузке страницы, инициализация выполнится сразу, независимо от необходимости.
Добавим ленивую обёртку с кэшированием результата:
function lazy(fn) {
let initialized = false;
let value;
return () => {
if (!initialized) {
value = fn();
initialized = true;
}
return value;
};
}Функция выполнится только при первом вызове, результат сохранится внутри замыкания и будет переиспользоваться.
Подключение:
const getAnalytics = lazy(initAnalytics);
Пока
getAnalytics() не вызван, инициализация не происходит.Использование:
getAnalytics().track("page_view");Инициализация происходит в этой точке и больше не повторяется.
Пример с DOM (предполагается, что DOM уже доступен):
const getModal = lazy(() => {
const el = document.createElement("div");
el.textContent = "Modal";
document.body.append(el);
return el;
});Элемент создаётся только при первом обращении:
getModal().style.display = "block";
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥12❤9👍9
Извлекаем и обрабатываем выделенный текст — Selection API
Selection API позволяет получать выделение пользователя в DOM (кроме
Получаем выделенный текст:
Отслеживаем изменения выделения:
Извлекаем детали выделения:
Удобный хелпер:
Использование:
🔥 Такой пример полезен для практики работы с браузерными
📣 JS Ready | #практика
Selection API позволяет получать выделение пользователя в DOM (кроме
<input> и <textarea>, где нужно использовать selectionStart/selectionEnd). API подходит для подсветки, анализа, сохранения выделений и запуска контекстных действий.Получаем выделенный текст:
const text = window.getSelection().toString();
console.log("Выделено:", text);
Отслеживаем изменения выделения:
document.addEventListener("selectionchange", () => {
const t = window.getSelection().toString();
if (t) console.log("Новое выделение:", t);
});Извлекаем детали выделения:
const sel = window.getSelection();
console.log("anchorNode:", sel.anchorNode);
console.log("focusNode:", sel.focusNode);
console.log("rangeCount:", sel.rangeCount);
Удобный хелпер:
function onSelect(callback) {
const handler = () => {
const text = window.getSelection().toString().trim();
if (text) callback(text);
};
document.addEventListener("selectionchange", handler);
return () => document.removeEventListener("selectionchange", handler);
}Использование:
const unsubscribe = onSelect(selected => {
console.log("Пользователь выделил:", selected);
});API, реакцией на системные события и динамическим управлением интерфейсом.Please open Telegram to view this post
VIEW IN TELEGRAM
👍11❤9🔥6🤝2
This media is not supported in your browser
VIEW IN TELEGRAM
Это не обучающие статьи, а глубокие разборы архитектуры, устройства языка, качества кода и масштабируемых решений. Здесь много про то, как писать код: принципы, ограничения языка, реальные инженерные компромиссы.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥12👍7🤝7
Проверяем наличие свойства без ловушек прототипа!
Часто нужно проверить, есть ли у объекта собственное свойство.
Некоторые пишут так:
Проблема в том, что этот способ небезопасен: метод может быть переопределён, объекта может вообще не быть прототипа и код становится хрупким в edge-кейсах.
В современном JavaScript есть корректный и нативный способ —
Он не зависит от прототипа объекта, не ломается, если
Для сравнения,
🔥
📣 JS Ready | #совет
Часто нужно проверить, есть ли у объекта собственное свойство.
Некоторые пишут так:
obj.hasOwnProperty('key');Проблема в том, что этот способ небезопасен: метод может быть переопределён, объекта может вообще не быть прототипа и код становится хрупким в edge-кейсах.
В современном JavaScript есть корректный и нативный способ —
Object.hasOwn:
Object.hasOwn(obj, 'key');
Он не зависит от прототипа объекта, не ломается, если
hasOwnProperty затёрт и работает даже с Object.create(null).const dict = Object.create(null);
dict.x = 1;
Object.hasOwn(dict, 'x'); // true
Для сравнения,
in ведёт себя иначе:'a' in obj; // true — даже если свойство в прототипе
Object.hasOwn проверяет только то, что реально лежит в объекте.Please open Telegram to view this post
VIEW IN TELEGRAM
❤11👍8🔥7
Map — это удобная структура данных для хранения пар ключ - значение, где ключом может быть что угодно, а порядок элементов сохраняется.
На картинке — часто используемые методы Map: от добавления и получения значений до перебора данных.
Сохрани, чтобы не забыть!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13❤7👍7🤝2