truefrontender | Unsorted

Telegram-канал truefrontender - True Frontender

1137

Сборная солянка про фронтенд. JavaScript, React, TypeScript, HTML, CSS — здесь обсуждаем всё, что связано с веб-разработкой! Связь: @pmowq

Subscribe to a channel

True Frontender

Шпаргалка по базовым типам в TypeScript

#typescript

Читать полностью…

True Frontender

Всем привет! Сегодня речь пойдет об свойстве overscroll-behavior. Это свойство позволяет контролировать поведение прокрутки за пределами документа или элемента, то есть когда пользователь достигает края страницы или элемента и продолжает прокручивать. Это особенно актуально в мобильных браузерах, где стандартное поведение может включать эффект "отскока", что не всегда желательно.

overscroll-behavior имеет три возможных значения:
auto - стандартное поведение прокрутки, когда прокрутка может передаваться родительскому элементу.
contain - предотвращает распространение прокрутки на родительский элемент, но сохраняет эффекты прокрутки.
none - полностью предотвращает прокрутку за пределами элемента, включая эффекты.

Пример использования:

body {
overscroll-behavior: none;
}


Этот код предотвратит "отскок" страницы при достижении верхнего или нижнего края в браузерах, поддерживающих это свойство.

Посмотреть и поскроллить можно тут - JsFiddle(тык)

#css

Читать полностью…

True Frontender

Привет всем! Как всегда, начинаем наш понедельник с интересных задачек. Сегодня у нас - реализация кастомного метода filter. Эта задача не только проверит ваше понимание работы нативных методов и прототипов, но и общее логическое мышление.

Для начала вспомним, как работает стандартный метод filter. Он создаёт и возвращает новый массив, содержащий только те элементы исходного массива, для которых функция-предикат возвращает true. Наша задача - реализовать подобное поведение.

Алгоритм решения:
1. Определить функцию-метод в прототипе Array, делая его доступным для всех массивов.
2. Убедиться, что переданный аргумент является функцией, чтобы обеспечить корректную работу метода.
3. Создать новый массив для хранения элементов, которые пройдут фильтрацию.
4. Итерировать по всем элементам исходного массива.
5. Для каждого элемента вызвать функцию-предикат и, в зависимости от её результата, добавить элемент в новый массив или пропустить его.
6. Вернуть результирующий массив после завершения итерации.

Решение:

// Добавляем метод customFilter к прототипу Array
Array.prototype.customFilter = function(predicate) {
// Проверка, является ли переданный аргумент функцией
if (typeof predicate !== 'function') {
throw new TypeError(`${typeof predicate} is not a function`);
}

// Инициализация нового массива для отфильтрованных элементов
const result = [];

// Итерация по элементам исходного массива
for (let i = 0; i < this.length; i++) {
// Добавление элемента в результирующий массив, если предикат возвращает true
if (predicate(this[i], i, this)) {
result.push(this[i]);
}
}

// Возврат нового массива с элементами, прошедшими фильтрацию
return result;
};

// Использование кастомного метода customFilter
const numbers = [1, 2, 3, 4, 5];
const evenNumbers = numbers.customFilter(function(number) {
return number % 2 === 0;
});

console.log(evenNumbers); // Выведет: [2, 4]


Итог
Мы успешно расширили прототип Array, добавив к нему наш кастомный метод customFilter. Это не только помогло нам глубже понять механизм работы нативного метода filter, но и показало, как можно расширять стандартные объекты для добавления новой функциональности.

Встречали ли вы подобные задачи на собеседованиях?

#interview #javascript

Читать полностью…

True Frontender

Простой и интересный эффект "пульсации" на чистом CSS, который может использоваться для привлечения внимания к какому-либо действию, например, к подписке. Этот эффект создается с использованием анимаций CSS и keyframes, делая кнопку более заметной и привлекательной для пользователя.

Посмотреть можно тут - JsFiddle(тык)

Читать полностью…

True Frontender

Вы знаете о свойстве scroll-padding? Если нет, то этот пост будет для вас полезен. А если да, то просто поддержите реакцией 😏

Что такое scroll-padding?
scroll-padding устанавливает отступы внутри контейнера, которые применяются при прокрутке к определенному элементу по якорной ссылке. Это свойство гарантирует, что целевой элемент будет отображаться в пределах видимой области, не перекрываясь другими элементами.

Пример использования
Представьте, что на вашем сайте есть статья с несколькими разделами и фиксированное меню навигации сверху. Вы хотите, чтобы при выборе раздела в меню страница прокручивалась к этому разделу, но при этом раздел не скрывался за меню.

Посмотреть пример реализации можно здесь - JsFiddle(тык).

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

Читать полностью…

True Frontender

Привет! Сегодня мы разберем классическую джуновскую задачу с собеседований. Мы узнаем, как определить количество повторений каждого элемента в массиве.

Задача
У нас есть массив, который может содержать как уникальные, так и повторяющиеся элементы. Наша цель - выяснить, сколько раз каждый элемент встречается в этом массиве.

Пример
Возьмем массив хештегов: ["#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));


А вы встречали подобные задачи? Делитесь своими мыслями о других способах решения этой задачи или предлагайте свои задачи на будущие разборы.

#interview #javascript

Читать полностью…

True Frontender

Всем привет 👋! Сегодня мы затронем еще одну интересную тему в JavaScript - IIFE (Immediately Invoked Function Expression) и их взаимодействие с контекстом this.

Что такое IIFE?
IIFE – это функции, которые вызываются немедленно после их определения. Они служат для создания изолированного пространства имен и защиты области видимости.

Пример IIFE:

(function() {
console.log("Эта функция вызовется немедленно!");
})();


А что насчет this в IIFE?
Контекст this в JavaScript может меняться в зависимости от того, как и где функция вызывается. В IIFE, если они не стрелочные функции, this обычно ссылается на глобальный объект window (undefined в строгом режиме). Это означает, что независимо от того, где IIFE вызывается, this внутри нее будет указывать на глобальный контекст, если только явно не привязан к другому объекту через методы call, apply или bind.

Пример с this в IIFE:
(function() {
console.log(this); // Обычно это будет "window"
})();

const obj = {
test: function() {
(function() {
console.log(this);
})();
}
};

obj.test();
// "this" все еще будет указывать на "window", а не на "obj"


Особенности IIFE:
- IIFE создают свою область видимости, что предотвращает конфликты имен и защищает переменные.
- В IIFE this может вести себя неожиданно, его поведение зависит от контекста вызова.
- Могут принимать параметры, что позволяет еще больше контролировать их поведение.

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

Заключение
IIFE – помогают в создании чистого, модульного и безопасного кода.
А как часто вы используете IIFE функции? 🤔

#javascript

Читать полностью…

True Frontender

Привет фронтендеры! Сегодня мы узнаем о полезном свойстве 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

Читать полностью…

True Frontender

Привет всем! Новая неделя - новые возможности для обучения. Надеюсь, вы успели отдохнуть) Сегодня мы разберем классическую задачу с собеседования - реализацию дебаунсинга (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 мс), независимо от того, насколько часто происходит событие.

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

А какие интересные задачи встречались вам на собеседованиях и как вам эта задача? Поделитесь своим опытом в комментариях!

#interview #javascript #patterns

Читать полностью…

True Frontender

Всех с пятницей! Сегодня хочу рассмотреть не очень известный, но очень полезный метод navigator.sendBeacon(). Этот метод позволяет отправлять асинхронные запросы на сервер перед закрытием страницы, и это открывает нам несколько интересных возможностей. Давайте разберемся, в чем его особенность и как его можно использовать.

Что такое sendBeacon?
Метод sendBeacon был введен для решения проблемы отправки данных на сервер при закрытии страницы или при уходе пользователя с сайта по ссылке.

Как работает sendBeacon?
navigator.sendBeacon(url, data) принимает два аргумента: url сервера, куда вы хотите отправить данные, и data – сами данные. Самое интересное, что отправка данных происходит асинхронно и браузер не ожидает ее завершения перед закрытием страницы.

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

Пример

window.addEventListener('unload', function() {
navigator.sendBeacon('/log', JSON.stringify({userAction: 'pageClose'}));
});


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

#javascript

Читать полностью…

True Frontender

Привет! Сегодня я хочу поговорить о принципе DRY (Don't Repeat Yourself) и поделиться своими мыслями о том, как его правильно применять.

Применение DRY не всегда означает стремление к избавлению от любого дублирования кода. На самом деле, ключ к успешному использованию DRY заключается в понимании, когда и как нужно обобщать код.

Вот простой и эффективный подход к применению DRY:
1. Когда вы сталкиваетесь с новой задачей, начните с решения, нацеленного на конкретный случай. Это позволяет быстрее разработать работающий код и лучше понять задачу.
2. Если похожая задача возникает во второй раз, используйте уже написанный код, адаптируя его под новые условия. Важно здесь отметить в коде, что произошло повторение, чтобы быть осведомленным о потенциальной необходимости в дальнейшем обобщении.
3. Когда вы сталкиваетесь с проблемой в третий раз, это является сигналом к обобщению. Теперь у вас есть достаточно контекста и понимания для создания универсального решения.

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

DRY — это не просто правило избегать дублирования кода, а скорее стремление к упрощению и улучшению архитектуры вашего проекта. Помните, что ключевым фактором здесь является баланс: найти золотую середину между частными решениями и обобщенными подходами.

А что вы думаете на счет DRY?

Читать полностью…

True Frontender

Привет 👋! Начнем эту неделю с задачи, которую я встретил на одном из собеседований. Эта задача может и не является популярной, но она достаточно интересна и имеет разные варианты.

Задача
Представьте, что перед вами банкомат, загруженный купюрами различных номиналов, причем каждого номинала в разном количестве. Ваша задача - выдать заданную сумму, используя купюры наибольшего номинала, при этом учитывая их доступное количество.

Пример
В банкомате имеются: 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));


А теперь интересно узнать ваше мнение! Как вам эта задача? Какие альтернативные способы решения этой задачи вы можете предложить?

#javascript #interview

Читать полностью…

True Frontender

Привет! Наконец-то наступила пятница 🍺 Я, как и многие, всегда жду выходные, потому что можно чуть дольше посидеть за компом и не волноваться о том, что просплю дейли. Сейчас, буквально за пару секунд, я поделился с вами частью своих планов на выходные. Так же быстро и легко можно делиться информацией с помощью 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 - этот метод позволяет проверить, поддерживает ли браузер обмен определенными типами данных, что предотвращает возможные ошибки.

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

Заключение
Web Share API - это мощный и простой инструмент, который может оказать значительное влияние на взаимодействие пользователей с вашим сайтом.

Читать полностью…

True Frontender

Привет, дорогие читатели 🤗! Уже наступила среда, а это значит, что половина недели успешно пройдена, и мы стали еще ближе к выходным 🪱
Сегодня хочу вместе с вами базово разобрать методологию BEM (Block, Element, Modifier) и её роль в организации CSS.

Что такое BEM?
BEM разделяет интерфейс на независимые блоки, что упрощает поддержку кода. Он состоит из трёх компонентов:
1. Блок - это независимый компонент интерфейса, например, кнопка или меню.
2. Элемент - это часть блока, выполняющая определённую функцию. Например, пункт в меню.
3. Модификатор - это свойство блока или элемента, определяющее его внешний вид или поведение, например, активный пункт меню.

Пример:

/* Блок */
.menu { ... }

/* Элемент */
.menu__item { ... }

/* Модификатор */
.menu__item_active { ... }


Преимущества использования BEM:
- Стили становятся более предсказуемыми. Вы сразу видите, какие стили относятся к конкретному блоку или элементу.
- Облегчается переиспользование компонентов. Блоки могут быть использованы в разных частях проекта без конфликтов стилей.
- Масштабируемость проекта улучшается. BEM идеально подходит для работы в больших командах и на крупных проектах.

Хорошие практики:
- Используйте имена классов, которые чётко описывают функцию элемента, а не его внешний вид. Например, menu__item_disabled лучше, чем menu__item_gray.
- Не бойтесь создавать новые блоки. Это лучше, чем перегружать существующий блок излишней функциональностью.
- Избегайте каскадных стилей в BEM. Стилизуйте каждый элемент напрямую через его класс, это делает ваш CSS более предсказуемым.

Примеры из реальной жизни:
Давайте представим, что у нас есть блок product-card для карточки товара. Внутри него могут быть элементы как product-card__title для названия, так и product-card__price для цены. Если мы хотим выделить карточку товара на распродаже, мы добавляем модификатор product-card_sale.
/* Блок */
.product-card { ... }

/* Элементы */
.product-card__title { ... }
.product-card__price { ... }

/* Модификатор */
.product-card_sale { ... }


Заключение
BEM - это не только о нейминге, это о том, как организовать CSS вашего проекта, чтобы он был более понятным, масштабируемым и легким в поддержке.

#css

Читать полностью…

True Frontender

С понедельником! Сегодня поговорим о паттерне Builder(строитель). Он актуален, когда речь идет о создании сложных интерфейсов. Паттерн помогает разбить процесс на управляемые этапы, делая код чище и более организованным.

Что такое паттерн "Строитель"?
Строитель - это порождающий паттерн проектирования, который позволяет создавать сложные объекты, разделяя их создание на разные этапы. Это полезно, когда объект должен быть создан в несколько этапов или имеет множество возможных конфигураций.

Применение
Паттерн часто применяется для создания сложных UI компонентов. Например, при создании формы с множеством полей, кнопок и валидационных правил. Использование паттерна помогает упростить и структурировать процесс.

Преимущества:
Чистый код - использование этапов в процессе создания обеспечивает повышенную читаемость и облегчает поддержку кода.
Гибкость - возможность добавлять новые этапы и компоненты, не затрагивая уже написанный код.
Изоляция - сложные аспекты создания объектов удобно управляются и инкапсулируются.

Пример реализации
Допустим, у нас есть задача создания сложного интерактивного диалогового окна. Используя паттерн "Строитель", мы можем разделить этот процесс на этапы: создание основного контейнера, добавление кнопок, настройка обработчиков событий и так далее.
Пример с кодом на прикрепленном изображении.

В этом примере:
1. ModalBuilder - класс, реализующий паттерн "Строитель". Он позволяет пошагово создавать модальное окно с заголовком, содержимым и кнопками.
2. Методы setTitle, addButton, и setContent позволяют задавать соответствующие части модального окна.
3. Метод build создает и возвращает готовый элемент модального окна, который затем может быть добавлен в DOM.

Заключение
Паттерн "Строитель" является мощным инструментом для упрощения создания сложных объектов. Он обеспечивает чистоту и структурированность кода, делая его более поддерживаемым и расширяемым. Использование этого паттерна поможет вам управлять сложными задачами создания интерфейса и повысит качество вашего кода.

#patterns

Читать полностью…

True Frontender

Привет! Сегодня мы разберем один из самых популярных и полезных паттернов проектирования в программировани - паттерн "фабрика".

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

Как работает фабрика?
Фабрика предлагает создать отдельный компонент, задача которого - инкапсулировать логику создания объектов. Это значит, что вместо того, чтобы вручную создавать каждый объект с помощью оператора new, вы делегируете эту задачу фабрике, которая определит, какой объект создать, исходя из предоставленных ей данных.

Пример
Допустим, у нас есть приложение, где нужно создавать разные типы уведомлений: error, info, и success. Вместо того, чтобы создавать каждый тип уведомления вручную, мы можем использовать фабрику для упрощения этого процесса.
Пример реализации в прикрепленном изображении.

Преимущества паттерна:
- Паттерн позволяет легко внести изменения в процесс создания объектов, не затрагивая код, который использует эти объекты.
- Добавление новых типов объектов не требует изменений в клиентском коде, достаточно расширить функциональность фабрики.
- Детали создания объектов скрыты от клиента, что упрощает использование и поддержку кода.

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

#javascript #patterns

Читать полностью…

True Frontender

Привет 👋
Завтра наступает один из самых теплых и романтических дней в году - День Святого Валентина! В этот день принято дарить своим любимым не только внимание и заботу, но и небольшие знаки внимания. В этом году я предлагаю вам не ограничиваться бумажными открытками. Я подготовил для вас демо валентинки, сделанной с использованием HTML, CSS.
Посмотреть можно тут - JsFiddle(тык) 🫰

#javascript #html #css

Читать полностью…

True Frontender

Всем привет 👋 Сегодня мы узнаем о структуре данных, называемой стеком, который работает по принципу LIFO (Last In, First Out) - последний пришёл, первым ушёл. Это можно сравнить со стопкой тарелок: последнюю поставленную тарелку вы возьмёте первой.

Что такое стек?
Стек - это абстрактная структура данных, представляющая собой коллекцию элементов, с двумя основными операциями: push, которая добавляет элемент в конец стека, и pop, которая удаляет последний добавленный элемент. Элементы в стеке следуют принципу LIFO, где последний добавленный элемент будет первым извлеченным.

Почему стек важен?
Основное преимущество стека - простота и эффективность. Добавление и удаление элементов происходит за постоянное время O(1), что делает стек идеальной структурой данных для решения задач, требующих частого доступа к последним добавленным элементам.

Реализация

class Stack {
constructor() {
this.items = {}; // Используем объект для хранения элементов
this.count = 0; // Счетчик для отслеживания размера стека
}

// Добавление элемента в стек
push(item) {
this.items[this.count] = item; // Добавляем элемент с индексом, равным текущему размеру стека
this.count++; // Увеличиваем размер стека
}

// Удаление элемента из стека
pop() {
if (this.isEmpty()) {
return undefined;
}
this.count--; // Уменьшаем размер стека
const result = this.items[this.count]; // Сохраняем верхний элемент стека
delete this.items[this.count]; // Удаляем верхний элемент из стека
return result; // Возвращаем удаленный элемент
}

// Проверка, пуст ли стек
isEmpty() {
return this.count === 0;
}

// Возврат верхнего элемента стека
peek() {
if (this.isEmpty()) {
return undefined;
}
return this.items[this.count - 1]; // Возвращаем верхний элемент стека без его удаления
}

// Размер стека
size() {
return this.count;
}

// Очистка стека
clear() {
this.items = {}; // Сбрасываем объект элементов
this.count = 0; // Сбрасываем счетчик размера стека
}
}

// Использование стека
const stack = new Stack();
stack.push('Первый');
stack.push('Второй');
console.log(stack.peek()); // 'Второй'
stack.pop();
console.log(stack.peek()); // 'Первый'


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

#javascript #datastructures

Читать полностью…

True Frontender

Привет! В этом посте мы рассмотрим, что такое EventBus, как он работает и как вы можете использовать этот паттерн в своих проектах.

Что такое EventBus?
EventBus - это паттерн проектирования, который предоставляет канал для связи между различными компонентами приложения через события. Это означает, что вместо того чтобы вызывать методы одного компонента из другого напрямую, компоненты могут отправлять и принимать события.

Как работает EventBus?
Основная идея заключается в том, что у вас есть централизованный объект, который управляет подписками на события и их оповещениями. Компоненты могут подписываться на события, которые их интересуют, и когда другой компонент отправляет это событие через EventBus, все подписанные компоненты получают уведомление и могут соответствующим образом отреагировать.

Пример реализации в прикрепленном изображении.

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

#patterns

Читать полностью…

True Frontender

Всем привет! В этом посте мы рассмотрим, что такое 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

Читать полностью…

True Frontender

Привет, фронтендеры! Сегодня мы обсудим один из самых популярных алгоритмов - бинарный поиск. Этот алгоритм часто встречается на собеседованиях, и не зря - владение бинарным поиском показывает вашу способность к алгоритмическому мышлению и умение работать с данными

Что такое бинарный поиск?
Бинарный поиск - это метод поиска элемента в отсортированном массиве. Вместо перебора каждого элемента, алгоритм делит массив на две части и сравнивает искомый элемент с элементом в середине. Если совпадения нет, он исключает половину элементов из дальнейшего поиска, сокращая область поиска вдвое. Этот процесс повторяется до тех пор, пока не будет найден искомый элемент или массив не окажется пустым.

Преимущества:
- В отличие от линейного поиска, бинарный поиск существенно сокращает время поиска, особенно в больших массивах.
- Алгоритм легко реализуется как в итеративной, так и в рекурсивной форме.

Алгоритм решения:
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; // Элемент не найден
}


Частые ошибки:
- Не правильно выбирать середину массива.
- Не обрабатывать корректно краевые случаи, например, когда массив пуст или содержит только один элемент.

Где используется?
Бинарный поиск применяется во многих областях, от баз данных до поиска в текстах и оптимизации алгоритмов.

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

#interview #javascript #algorithm

Читать полностью…

True Frontender

Привет! На очереди у нас декораторы. Может показаться, что это сложно, но на самом деле все не так страшно. Мы вместе разберемся, что это такое, как декораторы работают и почему они могут быть полезны в вашем коде.

Что такое декоратор?
Декоратор – это структурный паттерн проектирования, который позволяет динамически добавлять новую функциональность без изменения исходного кода.

Как работают декораторы?
Декораторы оборачивают исходную функцию, создавая вокруг неё дополнительный слой логики. Это может быть, например, логирование, измерение времени выполнения, контроль доступа, кэширование и многое другое. Главное преимущество такого подхода в его гибкости: можно легко добавлять или убирать функциональность, не затрагивая основную логику.

Пример из жизни
Представьте, что вы заказываете кофе. Вы можете добавить в него сироп, молоко, сливки - каждая добавка улучшает ваш заказ, не меняя основного продукта.

Пример реализации:

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 тоже является декоратором, так как добавляет новое поведение к функции, не изменяя ее первоначальную структуру. Почитать можно в этом посте(тык).

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

Минусы:
- Может усложнить архитектуру, особенно если есть много слоев декораторов.
- Дополнительные слои могут влиять на производительность.

Заключение
Декораторы - помогают нам делать код более модульным, гибким и легко расширяемым. Однако как и любой инструмент, их следует использовать с умом, учитывая потенциальные сложности и влияние на производительность.

#patterns

Читать полностью…

True Frontender

Привет! Сегодня наша тема – хук useReducer в React. Все знакомы с useState, но useReducer зачастую уходит в тень, хотя предлагает великолепные возможности для управления состоянием.

Что такое useReducer и когда его использовать?
useReducer - это хук, который позволяет управлять состоянием компонента более контролируемым и предсказуемым способом, особенно когда у вас сложная логика состояний или большое количество изменяемых данных.

Как работает useReducer?
useReducer принимает три аргумента:
1. Функция, которая определяет, как состояние должно изменяться в ответ на определённые действия. Эта функция принимает текущее состояние и действие в качестве аргументов и возвращает новое состояние.

function reducer(state, action) {
switch (action.type) {
// логика обработки действий
}
}


2. Начальное состояние, которое будет использоваться в первый момент, когда компонент рендерится.
const initialState = { count: 0 };


3. Необязательная функция для расчета начального состояния. Она принимает начальное состояние в качестве аргумента и возвращает фактическое начальное состояние.
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' });


Видите разницу? Вместо прямой модификации состояния, мы отправляем "действие" (action), которое описывает, что именно нужно сделать. Это упрощает отслеживание изменений состояния и делает код более предсказуемым.

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

#react

Читать полностью…

True Frontender

Всем привет! Как проходят ваши выходные? 🏖
Сегодня поговорим о важной, но иногда недооцененной особенности в React - ключах. Это тема, которая может показаться незначительной на первый взгляд, но на самом деле играет важную роль в поведении наших React-приложений.

Что такое ключи и зачем они нужны?
Ключи в React - это специальные атрибуты строкового типа, которые мы присваиваем элементам при их рендеринге. Они помогают React определять, какие элементы были изменены, добавлены или удалены.

Пример

const todoList = todos.map((todo) =>
<li key={todo.id}>{todo.text}</li>
);


Почему ключи важны?
- Ключи помогают React оптимизировать процесс обновления DOM. Когда ключи отсутствуют или неправильно назначены, React может тратить больше ресурсов на ненужные операции, например, на перерисовку всего списка вместо обновления одного элемента.
- Неправильное использование ключей может привести к странным багам, например, некорректному сохранению состояния компонентов.

Как работают ключи под капотом
Когда React рендерит список, он использует ключи для сопоставления элементов с их предыдущими состояниями. Это позволяет React выполнять только необходимые обновления в DOM, что значительно повышает производительность.

Идеальный ключ должен быть:
- Уникальным для каждого элемента в списке.
- Постоянным и не меняться при повторных рендерингах.

Лучшие практики:
- Используйте уникальные идентификаторы из ваших данных, например, ID из базы данных.
- Если уникальный ID отсутствует, подумайте над логически уникальным способом генерации ключей.

Заключение
Ключи - это не просто дополнительные атрибуты, а мощный инструмент, который обеспечивает эффективную и правильную работу наших приложений. Правильное использование ключей помогает избежать множества проблем, связанных с производительностью и поведением компонентов.

#react

Читать полностью…

True Frontender

Всем 👋! Сегодня мы узнаем про паттерн проектирования - Адаптер. Этот паттерн - настоящий спасательный круг в океане разнообразных интерфейсов и API.

Что это за паттерн?
Адаптер - это структурный паттерн проектирования, который позволяет объектам с несовместимыми интерфейсами работать вместе. Представьте, что у вас есть электрическое устройство с американской вилкой, а розетка - европейская. Чтобы подключить устройство, вам нужен адаптер, который преобразует один интерфейс в другой. То же самое и в программировании.

Пример
У нас есть приложение, которое уже использует систему логирования ConsoleLogger для отслеживания действий и ошибок.
Теперь мы хотим добавить поддержку новой системы логирования, например, FileLogger, но её интерфейс отличается от ConsoleLogger.
Пример с кодом на прикрепленном изображении.

Преимущества использования:
- Вы можете использовать старые компоненты с новыми интерфейсами и наоборот.
- Нет необходимости переписывать уже существующий код.
- Адаптер отделяет и скрывает детали реализации от клиентского кода.

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

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

#patterns

Читать полностью…

True Frontender

Приветствую всех! Сегодня мы обсудим одну из фундаментальных тем в 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

Читать полностью…

True Frontender

Привет! Сегодня рассмотрим простой алгоритм сортировки. Сортировка вставками (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]));


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

Заключение
Сортировка вставками является хорошим инструментом. Она обеспечивает хорошую производительность на небольших массивах и проста в понимании и реализации.

#interview #javascript #algorithm

Читать полностью…

True Frontender

Всем привет ✌️
В этой статье мы погрузимся в Flexbox - мощный инструмент CSS для создания гибких и адаптивных макетов. Рассмотрим основные понятия и ключевые свойства.

-> Читать статью

#css

Читать полностью…

True Frontender

Всем привет! Хочу вместе с вами разобрать интересную задачу с собеседований: создание функции 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


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

А какие необычные или запоминающиеся задачи вам доводилось решать на собеседованиях?

#interview #javascript

Читать полностью…

True Frontender

Привет всем! Вероятно, вы уже прочитали множество статей о git, но я хочу предложить вам прочитать еще и мой пост) Сегодня я поделюсь своими мыслями о лучших практиках, а также предоставлю вам пару ссылок на интересные ресурсы.

Что такое Git?
Git - это система управления версиями, позволяющая отслеживать изменения в файлах и координировать работу над ними между несколькими людьми. Основное преимущество Git - его распределенная природа, позволяющая каждому участнику проекта иметь свою локальную копию репозитория.

Лучшие практики использования Git:
- Регулярно сохраняйте изменения, делая мелкие коммиты. Это упрощает навигацию по истории изменений и откат к более ранним версиям при необходимости.
- Пишите понятные и подробные сообщения к коммитам. Описательные сообщения помогают другим членам команды понять сделанные изменения и причины этих изменений.
- Работайте в отдельных ветках для новых функций или исправлений. Это предотвращает возможные конфликты в основной ветке кода и способствует более организованной работе.
- Понимайте разницу между merge и rebase для эффективного объединения изменений. merge соединяет ветки, сохраняя историю изменений, в то время как rebase переформатирует историю для более чистой линейной последовательности.
- Используйте файл .gitignore для исключения временных или локальных файлов из репозитория. Это предотвращает добавление ненужных или конфиденциальных файлов в общий репозиторий.

Полезные ссылки:
1. Learn Git Branching - интерактивный туториал, который помогает понять концепции ветвления и слияния в git.
2. Visualizing Git - можно посмотреть, как команды git влияют на структуру репозитория. Отлично подходит для визуализации сложных процессов в git.

#git

Читать полностью…
Subscribe to a channel