Frontend | Вопросы собесов
Сайт: https://easyoffer.ru/ Все каналы: t.me/+xGeAw6ckJ4liYzQy Контакт для рекламы: @sendme_ads
Показати більше📈 Аналітичний огляд Telegram-каналу Frontend | Вопросы собесов
Канал Frontend | Вопросы собесов (@easy_javascript_ru) у мовному сегменті Російська є активним учасником. На даний момент спільнота об'єднує 17 407 підписників, посідаючи 7 467 місце в категорії Технології та додатки та 37 733 місце у регіоні Росія.
📊 Показники аудиторії та динаміка
З моменту свого створення невідомо, проект продемонстрував стрімке зростання, зібравши аудиторію у 17 407 підписників.
За останніми даними від 30 жовтня, 2026, канал демонструє стабільну активність. Хоча за останні 30 днів спостерігається зміна кількості учасників на -247, а за останні 24 години на -22, загальне охоплення залишається високим.
- Статус верифікації: Не верифікований
- Рівень залученості (ER): Середній показник залученості аудиторії становить 6.93%. Протягом перших 24 годин після публікації контент зазвичай збирає 4.37% реакцій від загальної кількості підписників.
- Охоплення публікацій: В середньому кожен допис отримує 1 206 переглядів. Протягом першої доби публікація в середньому набирає 761 переглядів.
- Реакції та взаємодія: Аудиторія активно підтримує контент: середня кількість реакцій на один пост – 4.
- Тематичні інтереси: Контент зосереджений навколо ключових тем, таких як ставь, браузер, html, border, flex.
📝 Опис та контентна політика
Автор описує ресурс як майданчик для висловлення суб'єктивної думки:
“Сайт: https://easyoffer.ru/
Все каналы: t.me/+xGeAw6ckJ4liYzQy
Контакт для рекламы: @sendme_ads”
Завдяки високій частоті оновлень (останні дані отримано 31 жовтня, 2026), канал підтримує актуальність та високий рівень охоплення публікацій. Аналітика показує, що аудиторія активно взаємодіє з контентом, що робить його важливою точкою впливу в категорії Технології та додатки.
function App() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>Count: {count}</button>;
}
Я разделяю бизнес-логику и представление
// CounterLogic.js
export function useCounter() {
const [count, setCount] = useState(0);
const increment = () => setCount(count + 1);
return { count, increment };
}
// Counter.js
import { useCounter } from "./CounterLogic";
function Counter() {
const { count, increment } = useCounter();
return <button onClick={increment}>Count: {count}</button>;
}
🟠Компонентный подход и повторное использование кода
Frontend-приложения должны строиться из переиспользуемых и изолированных компонентов. Это уменьшает дублирование кода и делает его понятным.
// Button.js (переиспользуемый компонент)
function Button({ onClick, children }) {
return <button onClick={onClick}>{children}</button>;
}
// Counter.js (использует Button)
function Counter() {
const [count, setCount] = useState(0);
return <Button onClick={() => setCount(count + 1)}>Count: {count}</Button>;
}
🟠Чистый код и читаемость
Код должен быть понятным не только мне, но и другим разработчикам.
Понятные имена переменных и функций. Вместо x → userAge, вместо doSmth() → calculateTotalPrice().
Меньше вложенности. Вместо кучи if и else, лучше использовать early return.
Разбиение кода на модули. Один файл = одна зона ответственности.
function getDiscountedPrice(price, discount) {
if (discount <= 0) return price;
return price - price * (discount / 100);
}
🟠Состояние приложения: локальное vs глобальное
В зависимости от сложности приложения нужно правильно управлять состоянием:
Локальное состояние – useState (React), ref (Vue) для простых данных внутри компонента.
Глобальное состояние – Redux, MobX, Zustand, Pinia, Context API – когда данные нужны многим компонентам.
Серверное состояние – React Query, SWR – когда данные приходят с API и их нужно кешировать.
🟠Следование принципам SOLID и DRY
DRY (Don't Repeat Yourself) – не повторяем код, используем функции, хуки, компоненты.
SOLID – например, принцип единственной ответственности (Single Responsibility Principle) гласит, что каждый компонент или функция должны решать только одну задачу.
function sendEmailAndSaveToDB(user) {
sendEmail(user.email);
saveUserToDatabase(user);
}
Лучше разделить логику
function sendEmail(email) { /* отправка письма */ }
function saveUserToDatabase(user) { /* сохранение в БД */ }
function registerUser(user) {
sendEmail(user.email);
saveUserToDatabase(user);
}
🟠Использование TypeScript
TypeScript помогает избежать ошибок и делать код предсказуемым.
type User = {
id: number;
name: string;
};
function getUserName(user: User): string {
return user.name;
}
🟠Документация и кодстайл
ESLint + Prettier → автоформатирование и проверка стиля.
JSDoc/TypeScript → документация функций и типов данных.
Storybook → для документирования UI-компонентов.
Ставь 👍 и забирай 📚 Базу знанийFunction и используются для указания контекста this при вызове функции. Хотя все три метода позволяют контролировать значение this внутри функции, между ними существуют ключевые различия в способе использования и поведении.
🚩Сall
Вызывает функцию, явно устанавливая this в первом аргументе. Остальные аргументы передаются в вызываемую функцию как есть.
function greet(message, name) {
console.log(${message}, ${name}. This is ${this});
}
greet.call("Earth", "Hello", "Alice"); // "Hello, Alice. This is Earth"
🚩Apply
Очень похож на call, но принимает аргументы в виде массива, а не по отдельности.
function greet(message, name) {
console.log(
${message}, ${name}. This is ${this}
);
}
greet.apply("Earth", ["Hello", "Alice"]); // "Hello, Alice. This is Earth"
🚩Bind
Создаёт новую функцию, которая, когда она вызывается, имеет установленный контекст this, указанный в первом аргументе. В отличие от call и apply, bind не вызывает функцию сразу, а возвращает новую функцию, которую можно вызвать позже.
function greet(message, name) {
console.log(
${message}, ${name}. This is ${this}
);
}
const greetEarth = greet.bind("Earth", "Hello", "Alice");
greetEarth(); // "Hello, Alice. This is Earth"
Ставь 👍 и забирай 📚 Базу знаний100% в CSS основывается на родительском элементе. Рассмотрим различные случаи и подходы.
🟠Растяжение элемента на 100% ширины (`width: 100%;`)
Элемент займет всю ширину своего родителя.
<div style="width: 300px; background: lightblue;">
<div style="width: 100%; background: coral;">Я растянут по ширине!</div>
</div>
🟠Растяжение элемента на 100% высоты (`height: 100%;`)
Элемент займет всю высоту родительского элемента.
<div style="height: 300px; background: lightblue;">
<div style="height: 100%; background: coral;">Я растянут по высоте!</div>
</div>
🟠Растяжение элемента на 100% ширины и высоты
Для растяжения элемента как по ширине, так и по высоте относительно родителя используются width: 100%; и height: 100%;.
<div style="width: 300px; height: 300px; background: lightblue;">
<div style="width: 100%; height: 100%; background: coral;">Растянут по ширине и высоте!</div>
</div>
🟠Растяжение относительно окна браузера (`viewport`)
Если элемент нужно растянуть на весь экран, используются единицы 100vw (ширина окна) и 100vh (высота окна).
<div style="width: 100vw; height: 100vh; background: coral;">
Я растянут на весь экран!
</div>
Для исключения полосы прокрутки можно использовать
width: calc(100vw - 16px); /* Учитывается ширина скролла */
🟠Использование `position: absolute`
Когда нужно растянуть элемент независимо от размера его содержимого, можно использовать position: absolute.
<div style="position: relative; width: 300px; height: 300px; background: lightblue;">
<div style="position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: coral;">
Я растянут абсолютно!
</div>
</div>
🟠Растяжение внутри Flexbox-контейнера
Flexbox автоматически растягивает вложенные элементы, если у них указаны свойства flex: 1 или align-items: stretch.
<div style="display: flex; width: 300px; height: 300px; background: lightblue;">
<div style="flex: 1; background: coral;">Я растянут по Flexbox!</div>
</div>
🟠Растяжение внутри Grid-контейнера
CSS Grid также позволяет растягивать элементы.
<div style="display: grid; width: 300px; height: 300px; background: lightblue;">
<div style="width: 100%; height: 100%; background: coral;">Я растянут внутри Grid!</div>
</div>
🟠Растяжение с учетом отступов
Если нужно учесть отступы (padding) или границы (border), используйте свойство box-sizing: border-box. Это гарантирует, что элемент с width: 100% и height: 100% не будет "выходить за пределы" из-за отступов.
<div style="width: 300px; height: 300px; background: lightblue;">
<div style="width: 100%; height: 100%; padding: 20px; box-sizing: border-box; background: coral;">
Я растянут с учетом отступов!
</div>
</div>
Ставь 👍 и забирай 📚 Базу знанийDate – встроенный объект
Библиотеку Intl.DateTimeFormat – для форматирования
Библиотеки (moment.js, date-fns, luxon) – для удобной работы
🚩Встроенный объект `Date`
Создание даты
const now = new Date(); // Текущая дата и время
console.log(now); // Например: 2025-02-25T12:34:56.789Z
Способы создания даты
new Date(); // Текущая дата
new Date(2025, 1, 25); // 25 февраля 2025 (месяцы с 0)
new Date("2025-02-25"); // ISO строка
new Date(1708850400000); // Unix timestamp (в мс)
Получение значений
const date = new Date();
console.log(date.getFullYear()); // 2025
console.log(date.getMonth()); // 1 (февраль, потому что январь — 0)
console.log(date.getDate()); // 25
console.log(date.getDay()); // 2 (вторник, потому что воскресенье — 0)
console.log(date.getHours()); // Часы
console.log(date.getMinutes()); // Минуты
console.log(date.getSeconds()); // Секунды
console.log(date.getTime()); // Время в миллисекундах (Unix timestamp)
Изменение даты
const date = new Date();
date.setFullYear(2030);
date.setMonth(11); // Декабрь
date.setDate(31);
console.log(date); // 31 декабря 2030
Форматирование даты
const date = new Date();
console.log(date.toDateString()); // "Tue Feb 25 2025"
console.log(date.toISOString()); // "2025-02-25T12:34:56.789Z"
console.log(date.toLocaleString()); // Локальное представление
console.log(date.toUTCString()); // "Tue, 25 Feb 2025 12:34:56 GMT"
Форматирование с Intl.DateTimeFormat
const date = new Date();
const formatter = new Intl.DateTimeFormat("ru-RU", {
year: "numeric",
month: "long",
day: "numeric",
weekday: "long",
});
console.log(formatter.format(date)); // "вторник, 25 февраля 2025 г."
🚩Библиотеки (более удобные способы)
date-fns (легковесная альтернатива Moment.js)
npm install date-fns
import { format, addDays } from "date-fns";
const now = new Date();
console.log(format(now, "dd.MM.yyyy HH:mm")); // 25.02.2025 15:30
console.log(addDays(now, 5)); // Дата + 5 дней
moment.js (устаревший, но популярный)
npm install moment
import moment from "moment";
const now = moment();
console.log(now.format("DD.MM.YYYY HH:mm")); // 25.02.2025 15:30
console.log(now.add(5, "days").format("DD.MM.YYYY")); // +5 дней
luxon (современная альтернатива Moment.js)
npm install luxon
import { DateTime } from "luxon";
const now = DateTime.now();
console.log(now.toFormat("dd.MM.yyyy HH:mm")); // 25.02.2025 15:30
console.log(now.plus({ days: 5 }).toFormat("dd.MM.yyyy")); // +5 дней
Разница между датами
const date1 = new Date("2025-02-25");
const date2 = new Date("2025-03-01");
const diff = date2 - date1; // Разница в миллисекундах
console.log(diff / (1000 * 60 * 60 * 24)); // Разница в днях (4)
Ставь 👍 и забирай 📚 Базу знанийuseEffect выполняется после рендера и отрисовки в браузере.
useLayoutEffect выполняется сразу после рендера, но перед отрисовкой в браузере.
То есть useLayoutEffect блокирует рендер, а useEffect — нет.
🚩Когда использовать `useEffect`?
useEffect выполняется асинхронно, после того как браузер отрисовал страницу.
Используется для:
- Запросов к API.
- Подключения WebSocket'ов или таймеров.
- Логирования данных.
- Изменения заголовка страницы (document.title).
import { useState, useEffect } from "react";
function App() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `Вы кликнули ${count} раз`;
}, [count]); // Запускается после рендера
return <button onClick={() => setCount(count + 1)}>Клик: {count}</button>;
}
🚩Когда использовать `useLayoutEffect`?
useLayoutEffect выполняется сразу после рендера, но перед тем, как браузер отобразит изменения.
Используется для
- Синхронных манипуляций с DOM.
- Измерения размеров элементов (getBoundingClientRect).
- Анимаций (например, при расчёте позиций).
import { useEffect, useLayoutEffect, useState } from "react";
function Example() {
const [width, setWidth] = useState(0);
useLayoutEffect(() => {
const box = document.getElementById("box");
setWidth(box.offsetWidth);
}, []);
return (
<div>
<div id="box" style={{ width: "100px", height: "50px", background: "red" }}></div>
<p>Ширина: {width}px</p>
</div>
);
}
Ставь 👍 и забирай 📚 Базу знанийfloat.
🚩Отмена обтекания с `clear: both;`
Если изображение обтекается текстом из-за float, нужно очистить обтекание с помощью clear: both;.
<img src="image.jpg" class="float-img">
<p class="clear-text">Этот текст не будет обтекать картинку.</p>
.float-img {
float: left; /* Изображение обтекается текстом */
margin-right: 10px;
}
.clear-text {
clear: both; /* Останавливает обтекание */
}
🚩Сделать изображение блочным (`display: block;`)
По умолчанию img – inline-block элемент, поэтому текст может располагаться рядом. Если сделать его display: block;, текст уйдёт вниз.
img {
display: block;
margin: 10px auto; /* Центрирование */
}
🚩Использовать `overflow: hidden;` для предотвращения наложений
Если у родителя есть float, можно использовать overflow: hidden; для очистки потока.
.container {
overflow: hidden; /* Очищает обтекание */
}
Ставь 👍 и забирай 📚 Базу знанийstate) или свойства (props) изменяются. Однако часто это приводит к ненужным рендерам, которые можно избежать.
🚩Почему важна оптимизация рендеринга?
🟠Производительность
Чем больше компонентов рендерится без необходимости, тем больше времени тратится на вычисления и обновления DOM.
🟠Экономия ресурсов
Избегая лишних рендеров, приложение работает быстрее, а пользовательский интерфейс становится более отзывчивым.
🟠Лучший UX
Плавная работа интерфейса критична для сложных приложений с большим количеством данных.
🚩Основные подходы к оптимизации рендеринга
🟠Мемоизация компонентов
React предоставляет утилиту React.memo, чтобы предотвращать ререндеринг компонента, если его props не изменились.
import React from 'react';
const MyComponent = React.memo(({ count }) => {
console.log('Рендер компонента');
return <div>Счётчик: {count}</div>;
});
// Использование
export default function App() {
const [count, setCount] = React.useState(0);
return (
<div>
<MyComponent count={count} />
<button onClick={() => setCount(count + 1)}>Увеличить</button>
</div>
);
}
🟠Использование `useMemo` и `useCallback`
Эти хуки используются для предотвращения повторных вычислений и создания функций при каждом рендере.
import React, { useMemo } from 'react';
function ExpensiveCalculationComponent({ number }) {
const calculatedValue = useMemo(() => {
console.log('Выполняются сложные вычисления...');
return number ** 2;
}, [number]); // Пересчитывается только если `number` изменился
return <div>Результат: {calculatedValue}</div>;
}
Пример useCallback
import React, { useCallback, useState } from 'react';
const Child = React.memo(({ onClick }) => {
console.log('Рендер дочернего компонента');
return <button onClick={onClick}>Кликни меня</button>;
});
function Parent() {
const [count, setCount] = useState(0);
const handleClick = useCallback(() => {
console.log('Кнопка нажата');
}, []); // Создаётся одна и та же функция между рендерами
return (
<div>
<Child onClick={handleClick} />
<button onClick={() => setCount(count + 1)}>Увеличить {count}</button>
</div>
);
}
🟠Разделение кода и ленивый рендеринг
Использование React.lazy и Suspense позволяет загружать компоненты только тогда, когда они необходимы.
import React, { Suspense } from 'react';
const LazyComponent = React.lazy(() => import('./LazyComponent'));
function App() {
return (
<Suspense fallback={<div>Загрузка...</div>}>
<LazyComponent />
</Suspense>
);
}
🟠Проверка зависимости в `useEffect`
Избегайте запуска побочных эффектов, если зависимости не изменились.
React.useEffect(() => {
console.log('Эффект сработал!');
}, [/* следите только за нужными зависимостями */]);
🟠Избегайте анонимных функций и объектов в `props`
Передача новых объектов и функций через props вызывает лишние рендеры.
<ChildComponent data={{ key: 'value' }} />
Лучше так
const data = { key: 'value' };
<ChildComponent data={data} />;
🟠Разделение больших компонентов
Если компонент слишком сложный, разделите его на более мелкие, чтобы React мог эффективно управлять состоянием и перерисовкой.
🟠Использование ключей при рендере списков
Каждый элемент списка должен иметь уникальный ключ, чтобы React мог правильно отслеживать изменения.
{items.map(item => (
<div key={item.id}>{item.name}</div>
))}
Ставь 👍 и забирай 📚 Базу знанийconst data = fetch("https://api.example.com/users"); // ❌ Ожидание ответа
console.log("Данные загружены:", data);
🟠Асинхронность решает эту проблему
Асинхронный код не блокирует выполнение программы
fetch("https://api.example.com/users")
.then(response => response.json())
.then(data => console.log("Данные загружены:", data));
console.log("Этот код выполнится сразу! 🚀");
🚩Как работает асинхронность в JS?
Callbacks (обратные вызовы) – старый способ.
Promises (fetch(), then/catch) – современный вариант.
async/await – удобный синтаксис для асинхронного кода.
async/await – лучший способ писать асинхронный код
async function getData() {
try {
let response = await fetch("https://api.example.com/users");
let data = await response.json();
console.log("Данные:", data);
} catch (error) {
console.error("Ошибка загрузки:", error);
}
}
getData();
console.log("Этот код выполняется, пока ждём данные!");
🚩Где нужна асинхронность?
Запросы к серверу
Чтение файлов
Таймеры
Работа с базами данных
Взаимодействие с пользователем (ожидание ввода)
Ставь 👍 и забирай 📚 Базу знаний