Сборная солянка про фронтенд. JavaScript, React, TypeScript, HTML, CSS — здесь обсуждаем всё, что связано с веб-разработкой! Связь: @pmowq
Привет! В этом посте мы рассмотрим, что такое EventBus, как он работает и как вы можете использовать этот паттерн в своих проектах.
Что такое EventBus?
EventBus - это паттерн проектирования, который предоставляет канал для связи между различными компонентами приложения через события. Это означает, что вместо того чтобы вызывать методы одного компонента из другого напрямую, компоненты могут отправлять и принимать события.
Как работает EventBus?
Основная идея заключается в том, что у вас есть централизованный объект, который управляет подписками на события и их оповещениями. Компоненты могут подписываться на события, которые их интересуют, и когда другой компонент отправляет это событие через EventBus, все подписанные компоненты получают уведомление и могут соответствующим образом отреагировать.
Пример реализации в прикрепленном изображении.
Заключение
EventBus позволяет уменьшить связность между компонентами и упрощает обмен данными и состояниями. Использование EventBus может сделать ваш код более чистым, организованным и гибким, что важно для поддержки и масштабирования сложных приложений.
#patterns
Всем привет! В этом посте мы рассмотрим, что такое enum
в TypeScript и какие существуют варианты объявления.
Что такое enum?
enum позволяет определить набор именованных констант. Использование enum делает код более читабельным и поддерживаемым, позволяя использовать именованные константы вместо магических чисел или строк.
Что такое const enum?const enum
- это особый вид перечисления в TypeScript, который полностью удаляется при компиляции, если используется в контексте, где это возможно. Это делает const enum
предпочтительным выбором для производительности, поскольку итоговый код становится меньше и быстрее.
Основные различия:
1. enum
компилируется в объекты, сохраняя свои ключи и значения, что позволяет выполнять итерацию по enum
или обратное преобразование из числа в строку. В отличие от этого, const enum
после компиляции оставляет только конкретные значения, тем самым уменьшая размер кода.
2. Так как const enum
полностью удаляются при компиляции, они не могут быть использованы для динамических операций, таких как обращение к значениям через ключи или итерация по членам перечисления в рантайме. enum
же остается в коде и поддерживает такие операции.
3. const enum
может улучшить производительность, поскольку исключает необходимость в создании и обращении к дополнительным объектам в рантайме. Это делает const enum
идеальным выбором для высокопроизводительных приложений или там, где размер имеет значение.
Что использовать?
- Используйте enum
, если вам нужен полный набор функций TypeScript и JavaScript, таких как обратное отображение (получение имени константы по ее значению) или динамическое обращение.
- Используйте const enum
, если вы цените производительность и размер вашего кода. Они особенно полезны в больших проектах, где каждый килобайт на счету.
Заключение
Выбор между enum
и const enum
в TypeScript зависит от ваших целей: если важна производительность и размер кода, const enum
- ваш выбор. Для более гибкого использования и возможности работы с перечислениями в рантайме подойдет enum
.
#typescript
Привет, фронтендеры! Сегодня мы обсудим один из самых популярных алгоритмов - бинарный поиск. Этот алгоритм часто встречается на собеседованиях, и не зря - владение бинарным поиском показывает вашу способность к алгоритмическому мышлению и умение работать с данными
Что такое бинарный поиск?
Бинарный поиск - это метод поиска элемента в отсортированном массиве. Вместо перебора каждого элемента, алгоритм делит массив на две части и сравнивает искомый элемент с элементом в середине. Если совпадения нет, он исключает половину элементов из дальнейшего поиска, сокращая область поиска вдвое. Этот процесс повторяется до тех пор, пока не будет найден искомый элемент или массив не окажется пустым.
Преимущества:
- В отличие от линейного поиска, бинарный поиск существенно сокращает время поиска, особенно в больших массивах.
- Алгоритм легко реализуется как в итеративной, так и в рекурсивной форме.
Алгоритм решения:
1. Инициализируем два указателя - start
и end
, которые указывают на начало и конец массива соответственно.
2. Пока start
не превышает end
, продолжаем поиск. Это гарантирует, что есть элементы для проверки.
3. Вычисляем индекс mid
как среднюю точку между start
и end
. Используем формулу mid = Math.floor(start + (end - start) / 2)
для предотвращения переполнения.
4. Если элемент в позиции mid
равен искомому x
, возвращаем mid
, так как элемент найден. Если элемент в mid
меньше x
, сужаем область поиска, устанавливая start
на mid + 1
. Если элемент в mid
больше x
, сужаем область поиска, устанавливая end
на mid - 1
.
5. Если start
превысит end
, элемент отсутствует в массиве и мы возвращаем -1
.
Пример реализации:
function binarySearch(arr, x) {
if (arr.length === 0) return -1; // Проверяем, не пустой ли массив
let start = 0;
let end = arr.length - 1;
while (start <= end) {
let mid = Math.floor(start + (end - start) / 2); // Вычисление середины
// Сравниваем элемент в середине с искомым значением
if (arr[mid] === x) {
return mid; // Элемент найден
} else if (arr[mid] < x) {
start = mid + 1; // Искомый элемент больше, продолжаем поиск в правой половине
} else {
end = mid - 1; // Искомый элемент меньше, продолжаем поиск в левой половине
}
}
return -1; // Элемент не найден
}
Привет! На очереди у нас декораторы. Может показаться, что это сложно, но на самом деле все не так страшно. Мы вместе разберемся, что это такое, как декораторы работают и почему они могут быть полезны в вашем коде.
Что такое декоратор?
Декоратор – это структурный паттерн проектирования, который позволяет динамически добавлять новую функциональность без изменения исходного кода.
Как работают декораторы?
Декораторы оборачивают исходную функцию, создавая вокруг неё дополнительный слой логики. Это может быть, например, логирование, измерение времени выполнения, контроль доступа, кэширование и многое другое. Главное преимущество такого подхода в его гибкости: можно легко добавлять или убирать функциональность, не затрагивая основную логику.
Пример из жизни
Представьте, что вы заказываете кофе. Вы можете добавить в него сироп, молоко, сливки - каждая добавка улучшает ваш заказ, не меняя основного продукта.
Пример реализации:
class Coffee {
cost() {
return 10;
}
}
class MilkCoffee {
constructor(coffee) {
this.coffee = coffee;
}
cost() {
return this.coffee.cost() + 2;
}
}
// Использование
const myCoffee = new MilkCoffee(new Coffee());
console.log(myCoffee.cost()); // 12
debounce
. Функция debounce
тоже является декоратором, так как добавляет новое поведение к функции, не изменяя ее первоначальную структуру. Почитать можно в этом посте(тык).Привет! Сегодня наша тема – хук useReducer
в React. Все знакомы с useState
, но useReducer
зачастую уходит в тень, хотя предлагает великолепные возможности для управления состоянием.
Что такое useReducer и когда его использовать?useReducer
- это хук, который позволяет управлять состоянием компонента более контролируемым и предсказуемым способом, особенно когда у вас сложная логика состояний или большое количество изменяемых данных.
Как работает useReducer?useReducer
принимает три аргумента:
1. Функция, которая определяет, как состояние должно изменяться в ответ на определённые действия. Эта функция принимает текущее состояние и действие в качестве аргументов и возвращает новое состояние.
function reducer(state, action) {
switch (action.type) {
// логика обработки действий
}
}
const initialState = { count: 0 };
function init(initialState) {
// Сложная логика для определения начального состояния
return initialState;
}
useReducer
, вы получите доступ к двум элементам: текущему состоянию и функции dispatch
. Функция dispatch
используется для отправки действий в ваш reducer.useState
вы бы сделали это так:const [count, setCount] = useState(0);
const increment = () => setCount(prevCount => prevCount + 1);
const decrement = () => setCount(prevCount => prevCount - 1);
useReducer
:const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { ...state, count: state.count + 1 };
case 'decrement':
return { ...state, count: state.count - 1 };
default:
return state
}
}
const [state, dispatch] = useReducer(reducer, initialState);
// Использование:
dispatch({ type: 'increment' });
dispatch({ type: 'decrement' });
useReducer
- позволяет сделать код более структурированным и упрощает управление сложными состояниями. Использование useReducer
не всегда необходимо, но в сложных сценариях он становится настоящим спасением. Всем привет! Как проходят ваши выходные? 🏖
Сегодня поговорим о важной, но иногда недооцененной особенности в React - ключах. Это тема, которая может показаться незначительной на первый взгляд, но на самом деле играет важную роль в поведении наших React-приложений.
Что такое ключи и зачем они нужны?
Ключи в React - это специальные атрибуты строкового типа, которые мы присваиваем элементам при их рендеринге. Они помогают React определять, какие элементы были изменены, добавлены или удалены.
Пример
const todoList = todos.map((todo) =>
<li key={todo.id}>{todo.text}</li>
);
Всем 👋! Сегодня мы узнаем про паттерн проектирования - Адаптер. Этот паттерн - настоящий спасательный круг в океане разнообразных интерфейсов и API.
Что это за паттерн?
Адаптер - это структурный паттерн проектирования, который позволяет объектам с несовместимыми интерфейсами работать вместе. Представьте, что у вас есть электрическое устройство с американской вилкой, а розетка - европейская. Чтобы подключить устройство, вам нужен адаптер, который преобразует один интерфейс в другой. То же самое и в программировании.
Пример
У нас есть приложение, которое уже использует систему логирования ConsoleLogger
для отслеживания действий и ошибок.
Теперь мы хотим добавить поддержку новой системы логирования, например, FileLogger
, но её интерфейс отличается от ConsoleLogger
.
Пример с кодом на прикрепленном изображении.
Преимущества использования:
- Вы можете использовать старые компоненты с новыми интерфейсами и наоборот.
- Нет необходимости переписывать уже существующий код.
- Адаптер отделяет и скрывает детали реализации от клиентского кода.
Когда стоит использовать?
- Когда у вас есть классы с несовместимыми интерфейсами, которые должны работать вместе.
- Когда вы хотите использовать существующий класс, но его интерфейс не соответствует остальной части вашего кода.
Заключение
Адаптер помогает сделать системы более гибкими и масштабируемыми, обеспечивая возможность использовать новые компоненты с минимальными изменениями в существующем коде.
#patterns
Приветствую всех! Сегодня мы обсудим одну из фундаментальных тем в CSS - вес селекторов. Это поможет нам понять, как браузер решает, какие стили применять к элементу, когда имеется несколько конкурирующих правил.
Что такое вес селекторов?
Вес селектора определяет приоритетность стилей. Когда несколько селекторов претендуют на изменение одного и того же элемента, в игру вступает вес селекторов. Браузер следует правилам специфичности, чтобы определить, какие стили применять.
Вес селектора определяется на основе трех типов селекторов:
1. ID селекторы (#id
) имеют самый высокий вес.
2. Классы, псевдоклассы и атрибуты (.class
, :hover
, [type="text"]
) следуют за ID по весу.
3. Элементы и псевдоэлементы (например, div
, ::after
) имеют самый низкий вес.
Специфичность селектора можно представить в виде чисел, например: 0,1,0,0 для ID селектора, 0,0,1,0 для класса, и 0,0,0,1 для типа элемента. Но почему используются именно четыре цифры? Это связано с тем, что первая цифра отвечает за инлайновые стили (атрибут style
в HTML), которые имеют самый высокий приоритет.
Правила подсчета:
Специфичность считается слева направо: инлайновые стили, затем ID, классы/псевдоклассы/атрибуты, и в конце элементы/псевдоэлементы. Более специфичный селектор переопределяет менее специфичные, даже если они объявлены позже.
Примеры:
- Селектор #header
(вес 0,1,0,0) переопределит .main .header
(вес 0,0,2,0) из-за наличия ID селектора.
- Селектор .button.active
(вес 0,0,2,0) будет иметь больший приоритет, чем .button
(вес 0,0,1,0) благодаря дополнительному классу.
- Селектор div span
(вес 0,0,0,2) будет менее специфичным, чем .element
(вес 0,0,1,0), несмотря на использование двух типов элементов.
Важные моменты:
- Универсальный селектор (*
), комбинаторы (например, +
, >
) и отрицание (:not()
) не влияют на вес.
- Стили, объявленные в атрибуте style HTML элемента, всегда имеют наивысший приоритет (за исключением !important
).
- Использование !important
в CSS объявлении может переопределить другие стили, независимо от их специфичности, но следует избегать его частого использования. В этом посте(тык) я делился своими мыслями на счет !important
.
Почему это важно?
Понимание веса селекторов критически важно для эффективной работы с CSS. Это помогает в избежании конфликтов стилей и позволяет писать более предсказуемый и управляемый код.
Заключение
Итак, мы разобрали, как браузер определяет, какие стили нужно применить к элементу, на основе веса селекторов. Это знание помогает создавать стили, которые ведут себя ожидаемо и легче поддаются дебаггингу. Понимание специфичности селекторов позволяет вам избегать излишнего использования !important
и обеспечивает более чистый, поддерживаемый код.
#css
Привет! Сегодня рассмотрим простой алгоритм сортировки. Сортировка вставками (Insertion Sort) — один из базовых, но в то же время эффективных алгоритмов сортировки. Этот метод часто используется из-за его простоты и эффективности на небольших массивах данных.
Что такое сортировка вставками?
Сортировка вставками — это алгоритм сортировки, который строит отсортированный массив элемент за элементом, вставляя каждый следующий элемент в подходящее место. Проще говоря, алгоритм берет элемент и вставляет его в правильное место среди уже отсортированных элементов.
Пример из жизни
Представьте, что у вас есть рука, полная игральных карт. Вы берете карту и, просматривая уже отсортированные в руке карты, вставляете ее в нужное место. Точно так же работает сортировка вставками с массивами данных.
Преимущества:
- Простота реализации.
- Хорошая производительность на небольших массивах.
- Эффективна для массивов, которые уже частично отсортированы.
- Не требует дополнительной памяти.
Пример реализации:
function insertionSort(array) {
// Проходим по массиву, начиная со второго элемента,
// так как первый элемент уже считается отсортированным
for (let currentIndex = 1; currentIndex < array.length; currentIndex++) {
let currentValue = array[currentIndex]; // Текущий элемент для вставки
let previousIndex = currentIndex - 1; // Индекс предыдущего элемента
// Идём назад по массиву и ищем подходящее место для текущего элемента.
// Элементы, которые больше текущего значения, сдвигаем на один шаг вправо.
while (previousIndex >= 0 && array[previousIndex] > currentValue) {
array[previousIndex + 1] = array[previousIndex]; // Сдвигаем элемент вправо
previousIndex--; // Переходим к следующему элементу для сравнения
}
// Вставляем текущий элемент в найденную позицию.
array[previousIndex + 1] = currentValue;
}
return array;
}
// Пример использования
console.log(insertionSort([9, 1, 15, 4, 0]));
Всем привет ✌️
В этой статье мы погрузимся в Flexbox - мощный инструмент CSS для создания гибких и адаптивных макетов. Рассмотрим основные понятия и ключевые свойства.
-> Читать статью
#css
Всем привет! Хочу вместе с вами разобрать интересную задачу с собеседований: создание функции sum
, которая позволяет выполнять цепочку вызовов вида sum(1)(2, 4)(3)
и так далее. Эта задача является отличным тестом на понимание работы замыканий в JavaScript.
Требования к функции:
1. Функция должна корректно обрабатывать несколько последовательных вызовов с любым количеством аргументов.
2. Каждый вызов функции с аргументами должен добавлять эти значения к общей сумме.
3. Если функция вызвана без аргументов, она должна возвращать текущее значение суммы.
Решение:
function sum(...args) {
let total = args.reduce((acc, cur) => acc + cur, 0);
function innerSum(...innerArgs) {
if (!innerArgs.length) return total;
total += innerArgs.reduce((acc, cur) => acc + cur, 0);
return innerSum;
}
return innerSum;
}
innerSum
вызывается без аргументов, она возвращает накопленный результат.
console.log(sum(1)(2, 4)(3)()); // Выведет 10
Привет всем! Вероятно, вы уже прочитали множество статей о git, но я хочу предложить вам прочитать еще и мой пост) Сегодня я поделюсь своими мыслями о лучших практиках, а также предоставлю вам пару ссылок на интересные ресурсы.
Что такое Git?
Git - это система управления версиями, позволяющая отслеживать изменения в файлах и координировать работу над ними между несколькими людьми. Основное преимущество Git - его распределенная природа, позволяющая каждому участнику проекта иметь свою локальную копию репозитория.
Лучшие практики использования Git:
- Регулярно сохраняйте изменения, делая мелкие коммиты. Это упрощает навигацию по истории изменений и откат к более ранним версиям при необходимости.
- Пишите понятные и подробные сообщения к коммитам. Описательные сообщения помогают другим членам команды понять сделанные изменения и причины этих изменений.
- Работайте в отдельных ветках для новых функций или исправлений. Это предотвращает возможные конфликты в основной ветке кода и способствует более организованной работе.
- Понимайте разницу между merge
и rebase
для эффективного объединения изменений. merge
соединяет ветки, сохраняя историю изменений, в то время как rebase
переформатирует историю для более чистой линейной последовательности.
- Используйте файл .gitignore
для исключения временных или локальных файлов из репозитория. Это предотвращает добавление ненужных или конфиденциальных файлов в общий репозиторий.
Полезные ссылки:
1. Learn Git Branching - интерактивный туториал, который помогает понять концепции ветвления и слияния в git.
2. Visualizing Git - можно посмотреть, как команды git влияют на структуру репозитория. Отлично подходит для визуализации сложных процессов в git.
#git
Привет! Сегодня хочу разобрать пользовательские события в JavaScript. Узнаем как эти события работают и как мы можем их использовать.
Что такое пользовательское событие?
Пользовательское событие - это событие, которое определено разработчиком, в отличие от стандартных событий, таких как click
, mouseover
и т.д. Это позволяет создавать более сложные и специфические сценарии взаимодействия в приложении.
Как создать пользовательское событие?
1. Использование конструктора Event
. Это базовый способ создания пользовательских событий.
const event = new Event('customEvent', {
bubbles: true, // Событие всплывает
cancelable: true // Событие можно отменить
});
// Добавление слушателя для события
document.addEventListener('customEvent', function(e) {
console.log('Пользовательское событие активировано');
});
// Инициирование события
document.dispatchEvent(event);
CustomEvent
. CustomEvent
- это расширение Event
, которое позволяет передавать дополнительные данные с событием.const customEvent = new CustomEvent('customEvent', {
detail: { message: 'Привет от CustomEvent' },
bubbles: true,
cancelable: true
});
document.addEventListener('customEvent', function(e) {
console.log('Сообщение: ', e.detail.message);
});
document.dispatchEvent(customEvent);
Разница между useEffect и useLayoutEffect в React
Хуки useEffect
и useLayoutEffect
в React часто вызывают путаницу из-за их схожести. Оба хука предназначены для выполнения побочных эффектов в функциональных компонентах, но они имеют ключевые различия в тайминге их выполнения.
useEffectuseEffect
используется для выполнения побочных эффектов в компоненте, таких как запросы данных, подписки или ручные изменения в DOM, которые не требуют немедленного выполнения и не блокируют визуальные обновления.
Особенности:
- Выполняется после отрисовки и коммита компонента в DOM.
- Не блокирует визуальные обновления, что делает его идеальным для большинства побочных эффектов.
- Используется для взаимодействий с внешними API и выполнения асинхронных операций.
useLayoutEffectuseLayoutEffect
работает аналогично useEffect
, но вызывается синхронно после всех изменений DOM, но перед перерисовкой на экране. Это значит, что все изменения, выполненные в useLayoutEffect
, будут отражены на экране сразу после его выполнения.
Особенности:
- Выполняется синхронно после всех изменений DOM, но до перерисовки.
- Используется для чтения или изменения DOM до того, как пользователь увидит обновления.
- Может вызывать блокировку визуальных обновлений, если содержит тяжелые вычисления.
Ключевые различия:
- useEffect
выполняется после отрисовки компонента, позволяя выполнять побочные эффекты без блокировки визуальных обновлений, в то время как useLayoutEffect
выполняется непосредственно после изменений в DOM и перед перерисовкой, что идеально подходит для задач, требующих немедленного чтения или изменения DOM.
- Использование useLayoutEffect
может привести к заметным задержкам в визуальных обновлениях, особенно если в нем содержатся тяжелые вычисления, тогда как useEffect
не оказывает такого влияния на процесс рендеринга.
- В большинстве случаев предпочтительнее использовать useEffect
для обработки побочных эффектов, а useLayoutEffect
следует использовать только тогда, когда необходимо синхронно взаимодействовать с DOM, например для измерения размеров элемента перед его отображением.
Заключение
Выбор между useEffect
и useLayoutEffect
зависит от требований к побочным эффектам в вашем компоненте. Хотя useEffect
является наиболее часто используемым хуком для побочных эффектов из-за его не блокирующего поведения, useLayoutEffect
предоставляет необходимую синхронность для определенных сценариев работы с DOM. Важно правильно выбирать между ними, чтобы обеспечить эффективную работу приложения и хороший пользовательский опыт.
#react
Вы знаете о свойстве scroll-padding
? Если нет, то этот пост будет для вас полезен. А если да, то просто поддержите реакцией 😏
Что такое scroll-padding?scroll-padding
устанавливает отступы внутри контейнера, которые применяются при прокрутке к определенному элементу по якорной ссылке. Это свойство гарантирует, что целевой элемент будет отображаться в пределах видимой области, не перекрываясь другими элементами.
Пример использования
Представьте, что на вашем сайте есть статья с несколькими разделами и фиксированное меню навигации сверху. Вы хотите, чтобы при выборе раздела в меню страница прокручивалась к этому разделу, но при этом раздел не скрывался за меню.
Посмотреть пример реализации можно здесь - JsFiddle(тык).
Заключениеscroll-padding
позволяет удобно настраивать поведение прокрутки, обеспечивая видимость контента даже при наличии фиксированных элементов на странице.
Привет! Сегодня мы разберем классическую джуновскую задачу с собеседований. Мы узнаем, как определить количество повторений каждого элемента в массиве.
Задача
У нас есть массив, который может содержать как уникальные, так и повторяющиеся элементы. Наша цель - выяснить, сколько раз каждый элемент встречается в этом массиве.
Пример
Возьмем массив хештегов: ["#javascript", "#react", "#patterns", "#css", "#interview", "#javascript", "#css"]
. Нам нужно определить, сколько постов приходится на каждый хештег.
Алгоритм решения:
1. Начинаем с пустого объекта, который будет хранить элементы массива как ключи и их количество как значение.
2. Используем метод reduce
для перебора каждого элемента в массиве.
3. Проверяем, существует ли уже такой ключ в аккумуляторе. Если да, увеличиваем его значение на 1
. Если нет - создаем ключ с начальным значением 1
.
4. После обработки всех элементов возвращаем аккумулятор как результат функции.
Решение
function countElements(arr) {
return arr.reduce((acc, element) => {
acc[element] = (acc[element] || 0) + 1;
return acc;
}, {});
}
// Пример использования
const tags = ["#javascript", "#react", "#patterns", "#css", "#interview", "#javascript", "#css"]
console.log(countElements(tags));
Всем привет 👋! Сегодня мы затронем еще одну интересную тему в JavaScript - IIFE (Immediately Invoked Function Expression) и их взаимодействие с контекстом this
.
Что такое IIFE?
IIFE – это функции, которые вызываются немедленно после их определения. Они служат для создания изолированного пространства имен и защиты области видимости.
Пример IIFE:
(function() {
console.log("Эта функция вызовется немедленно!");
})();
this
в JavaScript может меняться в зависимости от того, как и где функция вызывается. В IIFE, если они не стрелочные функции, this
обычно ссылается на глобальный объект window
(undefined
в строгом режиме). Это означает, что независимо от того, где IIFE вызывается, this
внутри нее будет указывать на глобальный контекст, если только явно не привязан к другому объекту через методы call
, apply
или bind
.(function() {
console.log(this); // Обычно это будет "window"
})();
const obj = {
test: function() {
(function() {
console.log(this);
})();
}
};
obj.test();
// "this" все еще будет указывать на "window", а не на "obj"
this
может вести себя неожиданно, его поведение зависит от контекста вызова.Привет фронтендеры! Сегодня мы узнаем о полезном свойстве CSS - counter-reset
. Это свойство позволяет нам управлять нумерацией элементов прямо в стилях, что может значительно сократить количество JavaScript кода.
Что такое counter-reset?counter-reset
- это CSS-свойство для создания или сброса CSS-счетчиков. Оно идеально подходит для нумерации списков, автоматической генерации заголовков разделов или подсчета элементов.
Как это работает?
Допустим, у вас есть статья с разделами и подразделами, и вы хотите автоматически пронумеровать их. Вот как может помочь counter-reset
:
1. Используйте counter-reset
, чтобы создать счетчик. Например, counter-reset: section
инициализирует счетчик с именем section
.
2. Примените counter-increment
для увеличения значения счетчика и content
с функцией counter()
для отображения. Например, content: counter(section) "."
добавит к элементу текст вида "1.", "2." и так далее.
3. Чтобы начать нумерацию заново, просто используйте counter-reset
снова.
Пример реализации можно посмотреть здесь - JSFiddle(тык)
Возможности и преимущества:
- counter-reset
позволяет управлять нумерацией на уровне CSS, уменьшая зависимость от HTML и JavaScript.
- Счетчики автоматически обновляются при добавлении или удалении элементов.
Заключениеcounter-reset
- это отличный инструмент, который может значительно упростить вашу работу при структурировании контента. Это свойство позволяет реализовывать различные интересные решения без лишнего кода.
#css
Привет всем! Новая неделя - новые возможности для обучения. Надеюсь, вы успели отдохнуть) Сегодня мы разберем классическую задачу с собеседования - реализацию дебаунсинга (debouncing). Хотя на практике мы часто используем готовые библиотеки для таких целей, на собеседованиях любят проверять понимание основных концепций.
Что такое debouncing?
Дебаунсинг - это техника уменьшения количества вызовов функции, которая может быть запущена повторно в короткий промежуток времени. Это особенно полезно для функций, вызываемых в ответ на события ввода или прокрутки, чтобы избежать чрезмерных вычислений или запросов к серверу.
Алгоритм решения:
1. Создайте функцию debounce
, которая принимает функцию func
и время ожидания wait
в миллисекундах.
2. Объявите переменную timeout
внутри debounce
, которая будет служить для хранения идентификатора таймера от setTimeout
.
3. Функция debounce
возвращает новую функцию, создающую замыкание с доступом к переменной timeout
и параметрам func
и wait
.
4. В начале каждого вызова возвращаемой функции отменяйте предыдущий таймер с помощью clearTimeout
.
5. Настройте новый таймер с помощью setTimeout
, который вызывает func
с текущими аргументами после задержки wait
.
6. Возвращаемая функция собирает все переданные ей аргументы с помощью оператора расширения ...args
и передает их в func
при вызове.
Реализация:
const debounce = (func, wait) => {
let timeout;
return (...args) => {
clearTimeout(timeout);
timeout = setTimeout(() => func(...args), wait);
};
};
// Пример использования
const debouncedInputHandler = debounce(event => {
console.log(event.target.value);
}, 500);
debounce
действует как декоратор, создавая обертку вокруг вашей функции и гарантируя, что она не будет вызываться чаще, чем раз в указанное время (в примере 500 мс), независимо от того, насколько часто происходит событие.Всех с пятницей! Сегодня хочу рассмотреть не очень известный, но очень полезный метод navigator.sendBeacon()
. Этот метод позволяет отправлять асинхронные запросы на сервер перед закрытием страницы, и это открывает нам несколько интересных возможностей. Давайте разберемся, в чем его особенность и как его можно использовать.
Что такое sendBeacon?
Метод sendBeacon
был введен для решения проблемы отправки данных на сервер при закрытии страницы или при уходе пользователя с сайта по ссылке.
Как работает sendBeacon?navigator.sendBeacon(url, data)
принимает два аргумента: url
сервера, куда вы хотите отправить данные, и data
– сами данные. Самое интересное, что отправка данных происходит асинхронно и браузер не ожидает ее завершения перед закрытием страницы.
Примеры использования:
- Отправка аналитики на сервер.
- Отслеживание ухода пользователя с сайта. Можно отправлять информацию о времени, проведенном на странице.
- Сохранение состояния приложения перед выходом пользователя, чтобы в следующий раз он мог продолжить с того же места.
Пример
window.addEventListener('unload', function() {
navigator.sendBeacon('/log', JSON.stringify({userAction: 'pageClose'}));
});
Привет! Сегодня я хочу поговорить о принципе DRY (Don't Repeat Yourself) и поделиться своими мыслями о том, как его правильно применять.
Применение DRY не всегда означает стремление к избавлению от любого дублирования кода. На самом деле, ключ к успешному использованию DRY заключается в понимании, когда и как нужно обобщать код.
Вот простой и эффективный подход к применению DRY:
1. Когда вы сталкиваетесь с новой задачей, начните с решения, нацеленного на конкретный случай. Это позволяет быстрее разработать работающий код и лучше понять задачу.
2. Если похожая задача возникает во второй раз, используйте уже написанный код, адаптируя его под новые условия. Важно здесь отметить в коде, что произошло повторение, чтобы быть осведомленным о потенциальной необходимости в дальнейшем обобщении.
3. Когда вы сталкиваетесь с проблемой в третий раз, это является сигналом к обобщению. Теперь у вас есть достаточно контекста и понимания для создания универсального решения.
Этот подход помогает избежать преждевременной абстракции и усложнения кода. Он также позволяет более глубоко понять проблему, прежде чем переходить к обобщенному решению.
DRY — это не просто правило избегать дублирования кода, а скорее стремление к упрощению и улучшению архитектуры вашего проекта. Помните, что ключевым фактором здесь является баланс: найти золотую середину между частными решениями и обобщенными подходами.
А что вы думаете на счет DRY?
Привет 👋! Начнем эту неделю с задачи, которую я встретил на одном из собеседований. Эта задача может и не является популярной, но она достаточно интересна и имеет разные варианты.
Задача
Представьте, что перед вами банкомат, загруженный купюрами различных номиналов, причем каждого номинала в разном количестве. Ваша задача - выдать заданную сумму, используя купюры наибольшего номинала, при этом учитывая их доступное количество.
Пример
В банкомате имеются: 2 купюры по 5000 рублей, 3 купюры по 1000 рублей, 5 купюр по 500 рублей и 10 купюр по 100 рублей. Пользователь хочет снять 8800 рублей. Каков будет ваш подход к выдаче этой суммы, используя купюры наибольшего номинала, которые доступны в банкомате?
Алгоритм решения:
1. Итерируемся по массиву denominations
.
2. Для каждого номинала определяем, сколько купюр мы можем использовать, чтобы приблизиться к запрашиваемой сумме, не превышая ее.
3. Вычитаем из запрашиваемой суммы соответствующее количество денег и добавляем данные о выданных купюрах в результат.
4. Продолжаем, пока не выдадим всю запрашиваемую сумму или пока не пройдем все доступные номиналы.
Решение:
const denominations = [
[5000, 2],
[1000, 3],
[500, 5],
[100, 10]
];
function withdraw(amount) {
let result = [];
for (let [denom, count] of denominations) {
let usableCount = Math.min(count, Math.floor(amount / denom));
if (usableCount > 0) {
amount -= usableCount * denom;
result.push([denom, usableCount]);
}
if (amount === 0) break;
}
return amount === 0 ? result : null; // Возвращаем null, если не можем выдать всю сумму
}
console.log(withdraw(8800));
Привет! Наконец-то наступила пятница 🍺 Я, как и многие, всегда жду выходные, потому что можно чуть дольше посидеть за компом и не волноваться о том, что просплю дейли. Сейчас, буквально за пару секунд, я поделился с вами частью своих планов на выходные. Так же быстро и легко можно делиться информацией с помощью Web Share API, о котором пойдет речь сегодня.
Что такое Web Share API?
Web Share API - это интерфейс программирования приложений, который позволяет приложениям использовать нативный механизм обмена данных операционной системы. Проще говоря, это позволяет пользователям делиться контентом, таким как текст, ссылки или файлы, напрямую через встроенные в их устройство функции обмена.
Как это работает?
Вызов navigator.share()
открывает нативное диалоговое окно обмена устройства. Этот метод принимает объект, который может содержать 4 свойства:
1. title
- заголовок
2. text
- текст
3. url
- ссылка
4. files
- массив файлов
Пример использования:
const shareData = {
title: '@TrueFrontender',
text: 'Подпишись!',
url: '/channel/TrueFrontender'
};
shareButton.addEventListener('click', () => {
if (!navigator.canShare) {
console.log('Браузер не поддерживает Web Share API')
}
if (navigator.canShare && navigator.canShare(shareData)) {
navigator.share(shareData)
.then(() => console.log('Поделились!'))
.catch((error) => console.log('Ошибка:', error));
} else {
console.log('Браузер не поддерживает Web Share API для данного типа данных.');
}
});
canShare
- этот метод позволяет проверить, поддерживает ли браузер обмен определенными типами данных, что предотвращает возможные ошибки.Привет, дорогие читатели 🤗! Уже наступила среда, а это значит, что половина недели успешно пройдена, и мы стали еще ближе к выходным 🪱
Сегодня хочу вместе с вами базово разобрать методологию BEM (Block, Element, Modifier) и её роль в организации CSS.
Что такое BEM?
BEM разделяет интерфейс на независимые блоки, что упрощает поддержку кода. Он состоит из трёх компонентов:
1. Блок - это независимый компонент интерфейса, например, кнопка или меню.
2. Элемент - это часть блока, выполняющая определённую функцию. Например, пункт в меню.
3. Модификатор - это свойство блока или элемента, определяющее его внешний вид или поведение, например, активный пункт меню.
Пример:
/* Блок */
.menu { ... }
/* Элемент */
.menu__item { ... }
/* Модификатор */
.menu__item_active { ... }
menu__item_disabled
лучше, чем menu__item_gray
.product-card
для карточки товара. Внутри него могут быть элементы как product-card__title
для названия, так и product-card__price
для цены. Если мы хотим выделить карточку товара на распродаже, мы добавляем модификатор product-card_sale
./* Блок */
.product-card { ... }
/* Элементы */
.product-card__title { ... }
.product-card__price { ... }
/* Модификатор */
.product-card_sale { ... }
С понедельником! Сегодня поговорим о паттерне Builder(строитель). Он актуален, когда речь идет о создании сложных интерфейсов. Паттерн помогает разбить процесс на управляемые этапы, делая код чище и более организованным.
Что такое паттерн "Строитель"?
Строитель - это порождающий паттерн проектирования, который позволяет создавать сложные объекты, разделяя их создание на разные этапы. Это полезно, когда объект должен быть создан в несколько этапов или имеет множество возможных конфигураций.
Применение
Паттерн часто применяется для создания сложных UI компонентов. Например, при создании формы с множеством полей, кнопок и валидационных правил. Использование паттерна помогает упростить и структурировать процесс.
Преимущества:
Чистый код - использование этапов в процессе создания обеспечивает повышенную читаемость и облегчает поддержку кода.
Гибкость - возможность добавлять новые этапы и компоненты, не затрагивая уже написанный код.
Изоляция - сложные аспекты создания объектов удобно управляются и инкапсулируются.
Пример реализации
Допустим, у нас есть задача создания сложного интерактивного диалогового окна. Используя паттерн "Строитель", мы можем разделить этот процесс на этапы: создание основного контейнера, добавление кнопок, настройка обработчиков событий и так далее.
Пример с кодом на прикрепленном изображении.
В этом примере:
1. ModalBuilder
- класс, реализующий паттерн "Строитель". Он позволяет пошагово создавать модальное окно с заголовком, содержимым и кнопками.
2. Методы setTitle
, addButton
, и setContent
позволяют задавать соответствующие части модального окна.
3. Метод build
создает и возвращает готовый элемент модального окна, который затем может быть добавлен в DOM.
Заключение
Паттерн "Строитель" является мощным инструментом для упрощения создания сложных объектов. Он обеспечивает чистоту и структурированность кода, делая его более поддерживаемым и расширяемым. Использование этого паттерна поможет вам управлять сложными задачами создания интерфейса и повысит качество вашего кода.
#patterns
С пятницей!
Наконец-то настал вечер пятницы, время, когда можно отдохнуть после долгой рабочей недели 🥳
Я полностью погрузился в работу и медленно, но верно приступаю к разработке большой стори. На выходных планирую уделить время созданию новых постов для вас. Надеюсь, посты на этой неделе были полезными для вас)
А как прошла ваша неделя, и чем вы планируете заниматься на выходных? Делитесь своими историями и планами в комментариях или просто поддержите этот пост реакциями ☺️
Всем хороших выходных 🏝
Всем ✌️! Сегодня я хочу поделиться с вами своими мыслями о !important
в CSS, этой маленькой, но мощной детали, которая часто становится предметом горячих дебатов.
Что такое !important?!important
- это декларация, которая может быть добавлена к стилю, чтобы повысить его приоритет над другими объявлениями. Например:
p {
color: blue !important;
}
<p>
, цвет текста будет синим.!important
.!important
может быть полезным.!important
.!important
.!important
только как крайнюю меру.!important
.!important
, чтобы облегчить понимание и поддержку кода в будущем.!important
это мощный инструмент, но его использование должно быть обоснованным и ограниченным. Осознанное применение !important
поможет избежать многих проблем, связанных с поддержкой и масштабированием ваших проектов.