Frontend Interview - собеседования по Javascript / Html / Css
10.4K subscribers
2.1K photos
118 videos
320 files
501 links
Канал для подготовки к собеседованиям по фронтенду

Админ, сотрудничество, реклама: @seniorFrontPromo, @maria_seniorfront

Купить рекламу: https://telega.in/c/frontendinterview

Канал в реестре РКН:
https://rknn.link/su
Download Telegram
​CORS для собеседований и работы

Если вы видите эту ошибку — вы не одиноки:
Access to fetch at 'https://api.site.com' from origin 'http://localhost:3000' has been blocked by CORS policy.


Разберем, почему это происходит, и как это починить. Что такое CORS, и для чего он нужен.

CORS (Cross-Origin Resource Sharing) - русского обозначения не имеет. Дословно "межисточниковый" обмен ресурсами.

Цель браузера: защитить пользователя от вредоносных сайтов за счет блокировки запросов к неразрешенным ресурсам.

Как работает:
- Браузер выполняет вызов ресурса.
- Получает заголовки Access-Control.
- Проверяет разрешенные заголовки на соответствие домена и запроса.
- Блокирует или разрешает чтение результата запроса.

Пример: пользователь открывает сайт evil.com. Если bank.com настроил CORS, JavaScript на evil.com не сможет прочитать ответ от bank.com/api/account.

CORS не защищает от кросс-доменных запросов (CSRF-атак). Браузер проверяет заголовки после получения ответа, блокируя передачу ответа в js код.

Заголовки CORS
# Разрешённые домены (один, список или *)
Access-Control-Allow-Origin: https://frontend.com

# Разрешённые HTTP-методы (список или *)
Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE

# Разрешённые заголовки для отправки(предварительный запрос)
Access-Control-Allow-Headers: Authorization, Content-Type, X-Requested-With

# Разрешённые для чтения заголовки (основной запрос)
Access-Control-Expose-Headers: Authorization, Content-Type, X-Requested-With

# Разрешить передачу кук/токенов
Access-Control-Allow-Credentials: true

# Кэшировать предварительный запрос на 600 сек (10 мин)
Access-Control-Max-Age: 600


Предзапросы (Preflight-запросы)
"Простые запросы" (GET, POST, HEAD без спец. заголовков) отправляются сразу.

"Сложные запросы", например, с методами PUT, DELETE или с нестандартными заголовками, сначала отправляют "предзапрос" (preflight request) методом OPTIONS.

Сервер должен ответить, разрешены ли такие запросы.

Например, перед вызовом GET с заголовком X-API-Key будет выполнен запрос:

http

/data HTTP/1.1
Origin: https://frontend.com
Access-Control-Request-Headers: X-API-Key


Сервер должен ответить:

http

HTTP/1.1 204 OK
Access-Control-Allow-Origin: https://frontend.com
Access-Control-Allow-Headers: X-API-Key


И только потом отправится основной запрос.

Лучшие практики CORS
1.Не используйте * для защищенных данных

Разрешайте только доверенные домены:
Access-Control-Allow-Origin: https://your-frontend.com


2.Для публичных API можно использовать *:

Access-Control-Allow-Origin: *


3.Куки = осторожно!

Если используете куки:
http

Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://frontend.com // Нельзя использовать *


4.Тестируйте предзапросы:

Для PUT, DELETE и запросов с Authorization всегда настраивайте обработку OPTIONS.

- Используйте Access-Control-Max-Age чтобы снизить нагрузку
- Настройте веб-сервер (Nginx/Apache) для оптимизации, обработки OPTIONS без запуска приложения

👉 @frontendInterview
👍3❤2
Angular Signals + RxJS: объединяем два реактивных мира в одном стейт-менеджере

Angular долгое время ассоциировался с RxJS. Даже слишком: многие разработчики ощущали, что без Observable ничего не работает. Но вот в Angular 17 появляются Signals — синхронная реактивность прямо из коробки. В 17+ — они становятся мейнстримом. Возникает вопрос: а что делать с RxJS? Выбрасывать?

Signals и RxJS — не конкуренты, а два мощных инструмента для решения разных задач. И если их правильно сочетать, можно построить удобную, масштабируемую и эффективную архитектуру

В этой статье мы:
- Разберёмся в различиях между Signals и RxJS
- Покажем, когда использовать что
- Сделаем свой собственный state-manager с красивым API
- И покажем, как всё это выглядит в реальном Angular-приложении

👉 @frontendInterview
❤1👍1
Какой метод аутентификации использует сторонние приложения для ограниченного доступа без передачи пароля?
Anonymous Quiz
33%
Двухфакторная аутентификация (2FA)
3%
Аутентификация по паролю
54%
OAuth
9%
Биометрическая аутентификация
Что такое mutations и actions в vuex?

Который является официальной библиотекой для управления состоянием в приложениях Vue.js, mutations (мутации) и actions (действия) играют ключевые роли в управлении состоянием. Они помогают обеспечивать предсказуемость изменения состояния и организовывают логику приложения.

Mutations (Мутации)
Это единственный способ изменить состояние в Vuex. Каждая мутация имеет тип и обработчик. Обработчик мутации получает состояние как первый аргумент, и дополнительный аргумент в качестве полезной нагрузки (payload), который можно использовать для передачи данных в мутацию. Мутации должны быть синхронными, чтобы изменения состояния можно было легко отслеживать. Это помогает делать отладку и логгирование более предсказуемыми.
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export default new Vuex.Store({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++;
},
incrementBy(state, payload) {
state.count += payload.amount;
}
}
});


Actions (Действия)
Действия используются для выполнения асинхронных операций или сложной бизнес-логики перед вызовом мутаций. Действия могут содержать произвольную асинхронную логику, такие как API-запросы, и затем вызывать мутации для изменения состояния. Действия вызываются с помощью метода dispatch и могут возвращать промисы, что полезно для обработки цепочек асинхронных операций.
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export default new Vuex.Store({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++;
}
},
actions: {
incrementAsync({ commit }) {
setTimeout(() => {
commit('increment');
}, 1000);
},
incrementByAsync({ commit }, payload) {
setTimeout(() => {
commit('incrementBy', payload);
}, 1000);
}
}
});


Взаимодействие между Mutations и Actions:

Mutations
Синхронно изменяют состояние.
Actions
Могут быть асинхронными и обычно вызывают мутации для изменения состояния.

Пример взаимодействия
// store.js
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export default new Vuex.Store({
state: {
message: ''
},
mutations: {
setMessage(state, message) {
state.message = message;
}
},
actions: {
fetchMessage({ commit }) {
setTimeout(() => {
const message = 'Hello from async action!';
commit('setMessage', message);
}, 2000);
}
}
});


Компонент
<template>
<div>
<p>{{ message }}</p>
<button @click="loadMessage">Load Message</button>
</div>
</template>

<script>
import { mapState, mapActions } from 'vuex';

export default {
computed: {
...mapState(['message'])
},
methods: {
...mapActions(['fetchMessage']),
loadMessage() {
this.fetchMessage();
}
}
};
</script>


👉 @frontendInterview
❤1
Web Design in easy steps, 7th Edition (2023)

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

👉 @frontendInterview
❤1
Break camelCase

Завершите решение так, чтобы функция разбивала camelCase пробелом.

Пример:
"camelCasing"  =>  "camel Casing"
"identifier" => "identifier"
"" => ""


👉 @frontendInterview
​Какие есть способы оптимизации рендеринга в react?

Это процесс снижения количества лишних перерисовок компонентов, что улучшает производительность приложения. React повторно рендерит компоненты, когда их состояние (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>
))}


👉 @frontendInterview
👍4❤1
​Как повернуть блок на 45 градусов?

Чтобы повернуть блок на 45 градусов, используется свойство CSS transform с функцией rotate. Это свойство позволяет применять различные трансформации к элементам, включая вращение, масштабирование, смещение и наклон.

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

.rotated-box {
width: 100px;
height: 100px;
background-color: lightblue;
transform: rotate(45deg);
}


Основной синтаксис
Угол поворота элемента. Может быть положительным или отрицательным значением в градусах (deg), радианах (rad), градусах (grad) или оборотах (turn).
transform: rotate(угол);   


Параметры
Угол поворота элемента. В данном случае элемент поворачивается на 45 градусов по часовой стрелке.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
.rotated-box {
width: 100px;
height: 100px;
background-color: lightblue;
transform: rotate(45deg);
}
</style>
</head>
<body>
<div class="rotated-box"></div>
</body>
</html>



Свойство transform
Позволяет применять различные визуальные эффекты к элементу, такие как вращение, масштабирование и смещение.
Функция rotate
Используется для вращения элемента на заданный угол. Положительные значения поворачивают элемент по часовой стрелке, отрицательные — против часовой стрелки.

Использование в реальных проектах
Вращение элементов может использоваться для создания интересных визуальных эффектов, таких как поворот иконок, изображений или блоков текста.

В комбинации с анимацией (@keyframes и transition), вращение может создавать динамичные и интерактивные пользовательские интерфейсы.

👉 @frontendInterview
👍2
JavaScript: массивы от А до Я для тех, кто только начал

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

👉 @frontendInterview
This media is not supported in your browser
VIEW IN TELEGRAM
«Почему у нас такая дерьмовая кодовая база?»

Как у нас проводят код-ревью:

👉 @frontendInterview
​sv, lv, dv

Одной из распространённых проблем, с которой сталкиваются разработчики сегодня это изменение размера viewport на мобильных устройствах. Было бы логичным полагать, что 100vh или 100% высоты экрана означали высоту, равную высоте экрана устройства, но vh не учитывает адресную строку и навигационную панель браузера на мобильных устройствах. Поэтому иногда высота контента оказывается слишком большой и появляется лишний скролл.

Это относительные единицы измерения, пришедшие на помощь знакомым vw, vh, vmin, vmax, с целью сделать процесс разработки более предсказуемым. svw и svh представляет собой наименьшую (smallest) ширину и высоту экрана с учётом элементов браузера, lvw и lvh — наибольшую (largest) ширину и высоту с учётом элементов браузера. dvw и dvh динамически (dynamic) высчитывает размер экрана при различных состояниях браузера, при открытой/закрытой адресной строке и навигационной панели браузера.

Пример
Ширина первого экрана будет равна 100% ширины вьюпорта, а высота — 100% высоты вьюпорта, причём размер будет динамически высчитываться при открытии/закрытии элементов браузера:
.vh {
min-height: 100vh;
}

.dvh {
min-height: 100dvh;
}



Динамический вьюпорт

dvw
Размер указывается в процентах от ширины вьюпорта (viewport width). 100dvw соответствует полной ширине вьюпорта и динамически пересчитывается при открытии/закрытии элементов браузера. 1dvw = 1% ширины вьюпорта.

dvh
Размер в процентах от высоты вьюпорта (viewport height). 100dvhсоответствует полной высоте вьюпорта и динамически пересчитывается при открытии/закрытии элементов браузера. 1dvh = 1% высоты вьюпорта.

dvmin
Размер в процентах от меньшей размерности вьюпорта и динамически пересчитывается при открытии/закрытии элементов браузера. Если высота меньше ширины (например, горизонтальная ориентация телефона), то расчёт будет вестись относительно высоты.

dvmax
Размер в процентах от большей размерности вьюпорта и динамически пересчитывается при открытии/закрытии элементов браузера. Если высота больше ширины (например, нормальная ориентация телефона), то расчёт будет вестись относительно высоты.

👉 @frontendInterview
👍7
Пять строк кода.

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

👉 @frontendInterview
❤3👍1
Flatten and sort an array

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

Пример:
Учитывая [[3, 2, 1], [4, 6, 5], [], [9, 7, 8]], ваша функция должна вернуть [1, 2, 3, 4, 5, 6, 7, 8, 9].

Дополнение:
Пожалуйста, помните, что JavaScript по умолчанию сортирует объекты в алфавитном порядке

👉 @frontendInterview
👍1
Замыкания в JavaScript

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

В следующем примере мы определяем функцию makeCounter(), которая фактически является фабричной функцией. При вызове она возвращает дочернюю функцию, которая имеет доступ к лексическому окружению внешней функции, то-есть функции makeCounter(). Таким образом, возвращаемая функция запоминает переменную counter и в последующем изменяет ее значение.

function makeCounter(initial = 0) {
let counter = initial;

return function() {
return counter += 1;
}
}

const counterA = makeCounter(0);

console.log(counterA()); // 1
console.log(counterA()); // 2

const counterB = makeCounter(100);

console.log(counterB()); // 101
console.log(counterB()); // 102


👉 @frontendInterview
👎3👍1
Как получить информацию о браузере пользователя?

Свойство window.navigator возвращает объект описания приложения (user agent), которое выполняет скрипт. В подавляющем большинстве случаев это приложение — браузер. Объект содержит свойства, описывающие браузер, и методы для выполнения действий.

Часто используемые свойства:
- userAgent возвращает строку, которая содержит название браузера.
navigator.userAgent
// "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:93.0) Gecko/20100101 Firefox/93.0"

- language возвращает предпочитаемый язык интерфейса в виде языкового тега.

- languages возвращает массив предпочитаемых языков в порядке предпочтительности. Первый в списке будет язык, который возвращает navigator.language.
navigator.language
// "ru"
navigator.languages
// ["ru", "en-US", "es-ES"]

- cookieEnabled возвращает true, если браузер пользователя поддерживает куки и они включены, false в противном случае.

👉 @frontendInterview
👍3