Dependency Injection (DI) — это паттерн, который упрощает управление зависимостями, но у него есть свои сложности и недостатки.
При использовании DI код может стать излишне сложным, особенно если внедрение зависимостей реализуется вручную или через сложные контейнеры.
class Service {
constructor(repository) {
this.repository = repository;
}
}Если DI используется через контейнеры, они могут замедлять выполнение программы, так как:
Создание объектов может занимать больше времени (особенно при ленивой инициализации).
Поиск зависимостей в контейнере тоже требует времени.
В Angular, NestJS и других фреймворках DI может потреблять больше ресурсов, чем обычное создание объектов.
Когда зависимости внедряются автоматически через контейнер, код становится менее очевидным.
@Injectable()
class Service {
constructor(private readonly repository: Repository) {}
}
Хотя DI часто называют удобным для тестирования, на практике могут возникнуть сложности:
Если контейнер создаёт объекты динамически, тесты могут работать нестабильно.
Нужно явно мокать зависимости, что может усложнять настройку тестов.
class Service {
constructor(repository) {
this.repository = repository;
}
}
const service = new Service(new Repository()); // Проблема при тестировании – жестко задана зависимостьЗдесь тестировать
Service сложно, потому что Repository создаётся вручную. Приходится использовать мок-объектыconst mockRepository = { getData: () => "mock data" };
const service = new Service(mockRepository);В маленьких проектах использование DI может быть излишним. Простое создание объектов может быть проще и понятнее, чем настройка DI-контейнера.
const repository = new Repository();
const service = new Service(repository);
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊3👍2🔥2
Да, Web Workers — часть HTML5. Это механизм для многопоточности в браузере: выполнение кода в фоновом потоке, без блокировки UI.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11👍2💊1
С появлением React Hooks в версии 16.8 (2019 год) классовые компоненты стали устаревшим способом создания компонентов. Сегодня функциональные компоненты с хуками заменяют классы. Давайте разберем почему.
Функциональные компоненты короче, читаются легче, а код становится чище.
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
increment = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<button onClick={this.increment}>
Счетчик: {this.state.count}
</button>
);
}
}Функциональный компонент (хуки делают код проще)
function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
Счетчик: {count}
</button>
);
}В классах жизненный цикл* компонента состоит из нескольких методов (
componentDidMount, componentDidUpdate, componentWillUnmount). class Timer extends React.Component {
constructor(props) {
super(props);
this.state = { time: 0 };
}
componentDidMount() {
this.timer = setInterval(() => {
this.setState({ time: this.state.time + 1 });
}, 1000);
}
componentWillUnmount() {
clearInterval(this.timer);
}
render() {
return <p>Время: {this.state.time} секунд</p>;
}
}Функциональный компонент (хуки делают все проще)
function Timer() {
const [time, setTime] = useState(0);
useEffect(() => {
const timer = setInterval(() => setTime(t => t + 1), 1000);
return () => clearInterval(timer);
}, []);
return <p>Время: {time} секунд</p>;
}Классовые компоненты используют экземпляры классов, а функциональные компоненты – просто функции.
Создают экземпляры
this Обрабатывают
setState Хранят лишние связи и контексты
Не создают
this Используют только нужные данные
Оптимизируются через React.memo
const Button = React.memo(({ onClick }) => {
console.log("Ререндер кнопки");
return <button onClick={onClick}>Нажми</button>;
});
function App() {
const [count, setCount] = useState(0);
const increment = useCallback(() => setCount(c => c + 1), []);
return (
<div>
<p>Счетчик: {count}</p>
<Button onClick={increment} />
</div>
);
}Раньше в классах код переиспользовали через HOC и Render Props, но это делало код сложным.
function withLogging(WrappedComponent) {
return class extends React.Component {
componentDidMount() {
console.log("Компонент монтирован");
}
render() {
return <WrappedComponent {...this.props} />;
}
};
}Хуки (
useEffect) делают код чище function useLogger() {
useEffect(() => console.log("Компонент монтирован"), []);
}
function MyComponent() {
useLogger();
return <p>Привет, мир!</p>;
}React официально рекомендует использовать функциональные компоненты
Dan Abramov (разработчик React)
Новые фичи React (Suspense, Server Components) создаются для функциональных компонентов
Классы не работают в React Server Components
Большинство современных библиотек (Redux Toolkit, React Query) рассчитаны на хуки
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
Это подход, при котором контент страницы отрисовывается по мере загрузки, а не дожидаясь полной загрузки всех ресурсов. Улучшает скорость восприятия и пользовательский опыт.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11
React.memo — это функция в React, которая используется для оптимизации производительности функциональных компонентов. Она предотвращает ненужные повторные рендеры, если пропсы компонента не изменились. В React каждый раз, когда родительский компонент обновляется, все его дочерние компоненты тоже ререндерятся, даже если их пропсы остались неизменными. Это может негативно сказаться на производительности, особенно если дочерний компонент выполняет сложные вычисления или рендерит большое количество данных.
React.memo решает эту проблему, запоминая (мемоизируя) предыдущий результат рендера и сравнивая его с новыми пропсами. Если пропсы не изменились, компонент просто использует закэшированное представление, а не ререндерится. React.memo — это функция высшего порядка (HOC), которая оборачивает функциональный компонентimport React from "react";
const MyComponent = ({ value }) => {
console.log("Рендер компонента!");
return <div>Значение: {value}</div>;
};
// Оборачиваем компонент в React.memo
const MemoizedComponent = React.memo(MyComponent);
export default MemoizedComponent;
React.memo vs. с React.memo Допустим, у нас есть родительский компонент, который изменяет состояние при каждом клике
import React, { useState } from "react";
import MemoizedComponent from "./MyComponent";
const Parent = () => {
const [count, setCount] = useState(0);
return (
<div>
<button onClick={() => setCount(count + 1)}>Увеличить</button>
<MemoizedComponent value="Привет, мир!" />
</div>
);
};
export default Parent;Если компонент всегда ререндерится из-за изменения пропсов – смысла в
memo нет. Если компонент рендерится быстро – оптимизация может быть ненужной, а проверка пропсов даже замедлит работу.
Если пропсы часто изменяются – кэширование теряет смысл, так как все равно ререндерится.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8💊2
- В CSS
- В препроцессорах
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13🔥6
Это структура данных, которая представляет собой упорядоченный список элементов. В JavaScript массивы могут содержать любые типы данных: числа, строки, объекты, другие массивы и даже функции.
Массивы помогают удобно хранить и обрабатывать наборы данных. Вместо того чтобы создавать множество переменных, можно использовать массив, чтобы хранить сразу несколько значений и работать с ними с помощью специальных методов.
Массивы позволяют:
Хранить несколько значений в одной переменной
Перебирать элементы с помощью циклов
Добавлять, удалять, изменять элементы
Выполнять операции, например, сортировку и фильтрацию
В JavaScript массив можно создать разными способами:
С использованием литерала массива
let fruits = ["яблоко", "банан", "апельсин"];
С использованием конструктора
Array let numbers = new Array(1, 2, 3, 4, 5);
Доступ к элементу массива осуществляется по индексу (начинается с 0):
let fruits = ["яблоко", "банан", "апельсин"];
console.log(fruits[0]); // "яблоко"
console.log(fruits[1]); // "банан"
Добавление элемента в конец
push() let arr = [1, 2, 3];
arr.push(4);
console.log(arr); // [1, 2, 3, 4]
Удаление последнего элемента
pop() arr.pop();
console.log(arr); // [1, 2, 3]
Добавление элемента в начало
unshift() arr.unshift(0);
console.log(arr); // [0, 1, 2, 3]
Удаление первого элемента
shift() arr.shift();
console.log(arr); // [1, 2, 3]
Перебор массива
forEach() arr.forEach(item => console.log(item));
Фильтрация элементов
filter() let evenNumbers = arr.filter(num => num % 2 === 0);
console.log(evenNumbers); // [2]
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Элемент сдвинется вниз на 5px от своего исходного положения, при этом останется в потоке документа.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10💊3🔥2
SPA (Single Page Application) и классический сайт (MPA – Multi Page Application) — это два разных подхода к созданию веб-приложений. Они отличаются по способу загрузки данных, навигации и производительности.
Каждый раз при переходе на новую страницу браузер запрашивает HTML с сервера. Сервер формирует страницу и отправляет готовый HTML.
<?php
echo "<h1>Добро пожаловать!</h1>";
?>
<a href="/about">О нас</a>
При первом заходе загружается одна HTML-страница и весь JavaScript. Дальше контент подгружается динамически через AJAX или Fetch API.
import React, { useState, useEffect } from "react";
function App() {
const [data, setData] = useState(null);
useEffect(() => {
fetch("/api/products")
.then(res => res.json())
.then(data => setData(data));
}, []);
return <div>{data ? JSON.stringify(data) : "Загрузка..."}</div>;
}
export default App;Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12💊1
Canvas:
- Рисование происходит в пикселях;
- Не интерактивно по умолчанию;
- Быстрее при большом количестве объектов;
- После отрисовки графика теряет «знание» о нарисованном.
SVG:
- Основан на DOM-элементах;
- Каждый элемент доступен и интерактивен;
- Удобен для меньшего числа элементов;
- Можно легко изменять стили и навешивать события.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊14
В JavaScript у событий есть специальные модификаторы, которые позволяют изменять поведение события, управлять его распространением, обработкой и связанной с ним логикой.
Этот метод предотвращает всплытие события вверх по дереву DOM.
По умолчанию, события в DOM распространяются по фазам: погружение (capturing) → цель (target) → всплытие (bubbling). Если вы хотите остановить обработку события на текущем элементе и не позволить ему "подняться" выше по дереву DOM, используйте
stopPropagation.<div id="parent" style="padding: 20px; background: lightblue;">
Родительский элемент
<button id="child">Дочерний элемент</button>
</div>
<script>
document.getElementById("parent").addEventListener("click", () => {
alert("Событие всплыло до родителя");
});
document.getElementById("child").addEventListener("click", (event) => {
alert("Событие на кнопке");
event.stopPropagation(); // Остановим всплытие
});
</script>
Этот метод, помимо остановки всплытия (как
stopPropagation), предотвращает выполнение других обработчиков на том же элементе. Если у одного и того же элемента есть несколько обработчиков для одного события, stopImmediatePropagation гарантирует, что после его вызова остальные обработчики не будут выполнены.<button id="myButton">Нажми меня</button>
<script>
const button = document.getElementById("myButton");
button.addEventListener("click", () => {
alert("Обработчик 1");
});
button.addEventListener("click", (event) => {
alert("Обработчик 2");
event.stopImmediatePropagation(); // Остановим все остальные обработчики
});
button.addEventListener("click", () => {
alert("Обработчик 3"); // Этот обработчик не выполнится
});
</script>
Этот метод отменяет поведение элемента по умолчанию.
Некоторые элементы (например, ссылки или формы) имеют стандартное поведение. Например:
- Клик по ссылке ведет на новый URL.
- Отправка формы перезагружает страницу.
С помощью
preventDefault можно предотвратить это поведение.<a href="https://example.com" id="link">Перейти на сайт</a>
<script>
const link = document.getElementById("link");
link.addEventListener("click", (event) => {
event.preventDefault(); // Останавливаем переход по ссылке
alert("Поведение ссылки отменено");
});
</script>
Это модификатор, который не является методом, а используется в настройках обработчика событий. Он указывает, что обработчик не вызывает
preventDefault. Этот модификатор помогает оптимизировать обработку событий, таких как прокрутка (scroll), делая их более производительными. Некоторые браузеры при обработке событий (например, touchstart или wheel) предполагают, что вы можете использовать preventDefault. Это замедляет прокрутку, так как браузеру нужно ждать завершения вашего обработчика. Указав passive: true, вы говорите браузеру, что не собираетесь отменять поведение.window.addEventListener("scroll", () => {
console.log("Скролл работает");
}, { passive: true });Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9💊4
CSS Grid — это двумерная система размещения элементов. Позволяет задавать строки и колонки, управлять размерами, промежутками и позиционированием контента по сетке.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥1
Браузер использует HTTP-заголовки и механизмы кэширования, чтобы решить, нужно ли сохранять ресурс (HTML, CSS, JS, изображения) и как долго его хранить.
Когда браузер загружает ресурс, сервер может сказать браузеру, как его кешировать, с помощью HTTP-заголовков.
HTTP/1.1 200 OK
Cache-Control: max-age=3600, public
ETag: "abc123"
Определяет, как долго ресурс должен храниться в кэше.
Cache-Control: max-age=86400, public
Определяет конкретную дату, до которой браузер может использовать кэшированный ресурс.
Expires: Wed, 26 Feb 2025 12:00:00 GMT
Позволяет браузеру узнать, изменился ли файл на сервере.
ETag: "abc123"
Если браузер снова запрашивает ресурс, он отправляет заголовок
If-None-Match: "abc123"
Дата последнего изменения ресурса.
Last-Modified: Tue, 25 Feb 2025 15:30:00 GMT
Браузер может отправить запрос с
If-Modified-Since: Tue, 25 Feb 2025 15:30:00 GMT
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍6
- Обе директивы предоставляют блочную область видимости.
- let идеально подходит для использования в случаях, когда значение переменной может изменяться.
- const используется для объявления переменных с неизменным значением.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍16
Event Loop (Цикл событий) – это механизм, который позволяет JavaScript работать асинхронно, обрабатывать события и не блокировать основной поток выполнения. Он решает несколько важных проблем, которые были бы сложны без него.
JavaScript работает в одном потоке, то есть выполняет код последовательно. Если одна операция занимает много времени (например, загрузка данных с сервера), выполнение всего кода остановилось бы, пока задача не завершится. Это привело бы к зависанию страницы.
Event Loop позволяет выполнять тяжёлые операции (например, запросы на сервер, таймеры) асинхронно, не блокируя основной поток.
console.log("1: Перед запросом");
setTimeout(() => {
console.log("2: Данные загружены");
}, 2000);
console.log("3: После запроса");Вывод в консоль
1: Перед запросом
3: После запроса
2: Данные загружены (спустя 2 секунды)
Если бы JavaScript не мог обрабатывать события асинхронно, то нажатия кнопок, прокрутка страницы и другие действия зависали бы, пока выполняется тяжёлая операция.
Event Loop ставит события (например,
click, keydown) в очередь и обрабатывает их только когда основной поток свободен. document.querySelector("button").addEventListener("click", () => {
console.log("Кнопка нажата!");
});Когда мы загружаем данные с сервера (
fetch, setTimeout, setInterval), они не приходят мгновенно. Без Event Loop браузер бы зависал в ожидании ответа. Асинхронные запросы (
fetch, XMLHttpRequest) выполняются в фоновом режиме. Когда ответ готов, он помещается в очередь задач и обрабатывается, когда основной поток освободится. console.log("Запрос данных...");
fetch("https://jsonplaceholder.typicode.com/posts/1")
.then(response => response.json())
.then(data => console.log("Данные получены:", data));
console.log("Код выполняется дальше!");Вывод
Запрос данных...
Код выполняется дальше!
(Спустя время) Данные получены: {id: 1, title: "..."}
Если в коде идёт сложная операция (например, сложные вычисления или рендеринг огромного списка), интерфейс зависнет.
Можно разбить задачу на части и выполнять её постепенно с помощью
setTimeout или requestAnimationFrame. let count = 0;
function heavyTask() {
for (let i = 0; i < 1e6; i++) {
count++;
}
console.log("Часть работы выполнена!");
if (count < 5e6) {
setTimeout(heavyTask, 0); // Даем Event Loop обработать другие задачи
}
}
heavyTask();
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12
Метод event.stopPropagation() останавливает всплытие события вверх по DOM. Также можно использовать event.stopImmediatePropagation() для прекращения вызова других обработчиков.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥3
Тип
any в TypeScript позволяет отключить проверку типов и использовать любую структуру данных, как в обычном JavaScript. Но
any убирает всю защиту TypeScript, поэтому его нужно использовать только в крайних случаях. Иногда сервер может вернуть разные структуры данных, и невозможно заранее определить точный тип.
async function fetchData(url: string): Promise<any> {
const response = await fetch(url);
return response.json();
}Лучший вариант — использовать интерфейсы вместо
any: interface User {
id: number;
name: string;
}
async function fetchUser(url: string): Promise<User> {
const response = await fetch(url);
return response.json() as User;
}Если проект на чистом JavaScript, добавление TypeScript может сломать код.
any помогает постепенно вводить строгую типизацию. function log(value: any) {
console.log(value);
}В
localStorage можно сохранить что угодно, поэтому при чтении данных тип неизвестен. const data: any = localStorage.getItem("user");Лучше сразу привести
any к нужному типуconst user = JSON.parse(localStorage.getItem("user") || "{}") as { id: number; name: string };Если функция должна работать с разными типами,
any может быть временным решением. function mergeObjects(obj1: any, obj2: any): any {
return { ...obj1, ...obj2 };
}Лучший вариант с
generic (T вместо any) function mergeObjects<T, U>(obj1: T, obj2: U): T & U {
return { ...obj1, ...obj2 };
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
Атрибут target определяет, где откроется ссылка или форма. Значения:
- _self — в текущем окне (по умолчанию);
- _blank — в новой вкладке;
- _parent — в родительском фрейме;
- _top — в полном окне браузера.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🔥6
В JavaScript, чтобы уничтожить объект
Web Worker, необходимо использовать метод terminate(). Этот метод останавливает выполнение worker'а, освобождает связанные с ним ресурсы и завершает его работу. После вызова terminate() объект worker больше не может быть использован.Web Worker позволяет выполнять тяжелые операции в фоновом потоке, не блокируя основной поток (UI-поток). Однако, если worker больше не нужен, он продолжает существовать и занимает ресурсы (память, процессорное время). Чтобы избежать утечек памяти и оптимизировать работу приложения, важно уничтожать worker, когда он больше не используется.
Вы вызываете метод
terminate() на экземпляре объекта worker. Это мгновенно останавливает выполнение фонового скрипта.// Создаем worker
const myWorker = new Worker('worker.js');
// Выполняем какие-то операции через worker
myWorker.postMessage('Hello, worker!');
// Завершаем работу worker, когда он больше не нужен
myWorker.terminate();
terminate() worker полностью уничтожается и больше не может отправлять или получать сообщения.onmessage), они автоматически удаляются.terminate() не приведет к ошибке, но никакие операции через него больше работать не будут.const worker = new Worker('worker.js');
// Отправляем сообщение
worker.postMessage('Start working');
// Завершаем работу worker
worker.terminate();
// Попытка отправить сообщение после уничтожения worker
worker.postMessage('Will this work?'); // Ничего не произойдет, worker уже завершенЕсли вы перезагружаете страницу или закрываете вкладку, все web worker автоматически уничтожаются браузером. Однако в рамках текущей сессии ответственность за уничтожение лежит на разработчике.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Обычно разбираются:
- Event Loop (очереди микротасков и макротасков);
- Call Stack и Web APIs;
- Garbage Collector;
- Внутренняя работа setTimeout, Promise, render;
- Оптимизация DOM, reflow/repaint;
- Компиляция и исполнение JS (V8, SpiderMonkey).
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13💊3