Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Высоко цените свое время и стремитесь успешно пройти собеседование по Frontend разработке? Тогда канал @easy_javascript_ru идеально подойдет для вас! Здесь собраны самые актуальные и интересные вопросы, которые могут встретиться на собеседованиях по Frontend. Уникальный контент поможет вам подготовиться к собеседованию и повысить свои шансы на успешное трудоустройство в сфере Frontend разработки. Не теряйте времени зря, присоединяйтесь к каналу, чтобы стать настоящим профессионалом в своей области! Для получения более подробной информации по вопросам рекламы обращайтесь к администратору по контактному номеру +7 921 632 6117. Также вы можете использовать специальные тесты и задачи для тренировки в каналах t.me/+T0COHtFzCJkwMDUy и t.me/+_tcX2w2EmvdmMTgy соответственно. Не упустите свой шанс найти лучшую работу в сфере Frontend разработки - переходите по ссылке t.me/+CgCAzIyGHHg0Nzky и начинайте свой успешный карьерный путь прямо сейчас!
08 Jan, 16:10
08 Jan, 09:10
blur
.blur
используется для выполнения действий, когда пользователь перестает взаимодействовать с элементом ввода. Например: Проверка корректности данных (валидация) после того, как пользователь заполнил поле.blur
помогает реализовать логику, связанную с завершением работы с конкретным элементом формы.blur
срабатывает, когда элемент теряет фокус, то есть пользователь:focus
, которое возникает при получении фокуса, blur
позволяет отследить момент завершения работы с элементом.onblur
).addEventListener
.<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Пример blur</title>
<script>
function validateInput(event) {
const input = event.target;
if (input.value.trim() === "") {
alert("Поле не должно быть пустым!");
}
}
document.addEventListener("DOMContentLoaded", () => {
const inputElement = document.getElementById("name");
inputElement.addEventListener("blur", validateInput);
});
</script>
</head>
<body>
<form>
<label for="name">Введите имя:</label>
<input type="text" id="name" name="name" />
<button type="submit">Отправить</button>
</form>
</body>
</html>
blur
не поддерживает всплытие (то есть не распространяется вверх по дереву DOM). Если нужно отслеживать потерю фокуса на уровне родительских элементов, используется делегирование с помощью события focusout
.// Работает только для конкретного элемента
element.addEventListener("blur", handler);
// Для делегирования используют focusout
parentElement.addEventListener("focusout", handler);
change
срабатывает только после изменения значения элемента и потери фокуса, тогда как blur
срабатывает в любом случае при потере фокуса, независимо от того, менялось ли значение.07 Jan, 16:10
07 Jan, 09:10
<div class="parent">
<p>Текст в параграфе.</p>
<div class="child">
<p>Другой текст в параграфе.</p>
</div>
</div>
.parent p {
color: blue;
font-size: 16px;
}
.child p {
font-size: 14px;
}
07 Jan, 07:00
06 Jan, 16:10
06 Jan, 09:10
npm init -y
npm install eslint --save-dev
.eslintrc
: npx eslint --init
npx eslint имя_файла.js
app.js
, выполнитеnpx eslint app.js
--fix
, чтобы исправить ошибки, которые можно исправить автоматически:npx eslint имя_файла.js --fix
package.json
. Откройте package.json
и добавьте следующий скрипт в раздел "scripts"
:"scripts": {
"lint": "eslint ."
}
npm run lint
{
"env": {
"browser": true,
"es2021": true
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module"
},
"rules": {
"indent": ["error", 4],
"linebreak-style": ["error", "unix"],
"quotes": ["error", "single"],
"semi": ["error", "always"]
}
}
05 Jan, 16:10
05 Jan, 09:10
import React, { Component } from 'react';
class MyComponent extends Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
componentDidMount() {
// Получаем доступ к DOM-элементу через реф
this.myRef.current.focus();
}
render() {
return <input type="text" ref={this.myRef} />;
}
}
export default MyComponent;
import React, { useRef, useEffect } from 'react';
const MyComponent = () => {
const myRef = useRef(null);
useEffect(() => {
// Получаем доступ к DOM-элементу через реф
myRef.current.focus();
}, []);
return <input type="text" ref={myRef} />;
};
export default MyComponent;
document.getElementById
или document.querySelector
. Это не рекомендуется, так как это противоречит философии React по работе с виртуальным DOM, но может быть полезно в некоторых случаях.import React, { useEffect } from 'react';
const MyComponent = () => {
useEffect(() => {
const element = document.getElementById('my-element');
element.style.color = 'red';
}, []);
return <div id="my-element">Hello, world!</div>;
};
export default MyComponent;
import React, { useRef, useLayoutEffect } from 'react';
const MyComponent = () => {
const myRef = useRef(null);
useLayoutEffect(() => {
// Получаем доступ к DOM-элементу через реф
myRef.current.style.color = 'blue';
}, []);
return <div ref={myRef}>Hello, world!</div>;
};
export default MyComponent;
04 Jan, 16:10
04 Jan, 09:10
console.log('Start');
setTimeout(() => {
console.log('Macrotask: setTimeout');
}, 0);
Promise.resolve()
.then(() => {
console.log('Microtask 1');
Promise.resolve().then(() => {
console.log('Microtask 2');
});
})
.then(() => {
console.log('Microtask 3');
});
console.log('End');
console.log('Start')
console.log('End')
setTimeout
.Promise.resolve().then(...)
.Start
End
Microtask 1
Microtask 2
Microtask 3
Macrotask: setTimeout
03 Jan, 16:10
03 Jan, 09:10
02 Jan, 16:10
02 Jan, 09:10
function fetchData(callback) {
setTimeout(() => {
const data = "some data";
callback(data);
}, 1000);
}
fetchData((result) => {
console.log(result);
});
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const data = "some data";
resolve(data);
}, 1000);
});
}
fetchData().then((result) => {
console.log(result);
}).catch((error) => {
console.error(error);
});
async function fetchData() {
return new Promise((resolve) => {
setTimeout(() => {
const data = "some data";
resolve(data);
}, 1000);
});
}
async function main() {
try {
const result = await fetchData();
console.log(result);
} catch (error) {
console.error(error);
}
}
main();
01 Jan, 16:10
01 Jan, 09:10
box-sizing
в CSS определяют, как учитываются отступы (padding
) и рамки (border
) при расчете размера элемента (width
и height
). Это влияет на окончательные размеры и внешний вид элемента на странице.box-sizing: content-box
, ширина и высота элемента включают только содержимое (content), но не включают отступы и рамки..element {
box-sizing: content-box; /* значение по умолчанию */
width: 200px;
padding: 20px;
border: 10px solid black;
}
border-box
, размеры элемента (width
и height
) включают содержимое, отступы и рамки. Это делает расчет размеров более простым и предсказуемым..element {
box-sizing: border-box;
width: 200px;
padding: 20px;
border: 10px solid black;
}
<div class="content-box">Content-box</div>
<div class="border-box">Border-box</div>
div {
margin: 10px;
padding: 20px;
border: 10px solid black;
}
.content-box {
box-sizing: content-box;
width: 200px;
height: 100px;
}
.border-box {
box-sizing: border-box;
width: 200px;
height: 100px;
}
31 Dec, 16:10
31 Dec, 09:10
loading="lazy"
в HTML).async
и defer
для асинхронной загрузки JavaScript, чтобы не блокировать рендеринг страницы. Встраивайте критические стили прямо в HTML, чтобы ускорить начальную отрисовку страницы.<img src="example.jpg" loading="lazy" alt="Пример изображения">
30 Dec, 16:10
30 Dec, 09:10
Proxy
является мощным и гибким способом перехвата и настройки операций с объектами, включая чтение и запись свойств.const handler = {
get(target, property) {
console.log(`Getting value of ${property}`);
return target[property];
},
set(target, property, value) {
console.log(`Setting value of ${property} to ${value}`);
target[property] = value;
return true;
}
};
const person = {
name: 'Alice',
age: 25
};
const proxyPerson = new Proxy(person, handler);
proxyPerson.name = 'Bob'; // Setting value of name to Bob
console.log(proxyPerson.name); // Getting value of name // Bob
Object.defineProperty
позволяет определить новое или изменить существующее свойство непосредственно на объекте, позволяя добавить геттеры и сеттеры для отслеживания изменений.const person = {
_name: 'Alice',
_age: 25
};
Object.defineProperty(person, 'name', {
get() {
console.log('Getting name');
return this._name;
},
set(value) {
console.log(`Setting name to ${value}`);
this._name = value;
}
});
Object.defineProperty(person, 'age', {
get() {
console.log('Getting age');
return this._age;
},
set(value) {
console.log(`Setting age to ${value}`);
this._age = value;
}
});
person.name = 'Bob'; // Setting name to Bob
console.log(person.name); // Getting name // Bob
person.age = 30; // Setting age to 30
console.log(person.age); // Getting age // 30
import { observable, autorun } from 'mobx';
const person = observable({
name: 'Alice',
age: 25,
setName(name) {
this.name = name;
},
setAge(age) {
this.age = age;
}
});
// Автоматически вызываемая функция при изменении наблюдаемого состояния
autorun(() => {
console.log(`Name: ${person.name}, Age: ${person.age}`);
});
person.setName('Bob'); // Name: Bob, Age: 25
person.setAge(30); // Name: Bob, Age: 30
MutationObserver
. Это не напрямую связано с объектами, но полезно для отслеживания изменений в элементах DOM.const targetNode = document.getElementById('target');
const config = { attributes: true, childList: true, subtree: true };
const callback = function(mutationsList, observer) {
for(let mutation of mutationsList) {
if (mutation.type === 'childList') {
console.log('A child node has been added or removed.');
}
else if (mutation.type === 'attributes') {
console.log('The ' + mutation.attributeName + ' attribute was modified.');
}
}
};
const observer = new MutationObserver(callback);
observer.observe(targetNode, config);
targetNode.setAttribute('data-test', 'value');
29 Dec, 16:10
29 Dec, 09:10
Proxy
в JavaScript позволяет перехватывать и настраивать операции, выполняемые с объектом, такие как чтение и запись свойств.const handler = {
get(target, property) {
console.log(`Getting value of ${property}`);
return target[property];
},
set(target, property, value) {
console.log(`Setting value of ${property} to ${value}`);
target[property] = value;
return true;
}
};
const person = {
name: 'Alice',
age: 25
};
const proxyPerson = new Proxy(person, handler);
proxyPerson.name = 'Bob'; // Setting value of name to Bob
console.log(proxyPerson.name); // Getting value of name // Bob
npm install mobx mobx-react
import { observable, autorun } from 'mobx';
import { observer } from 'mobx-react';
import React from 'react';
import ReactDOM from 'react-dom';
const appState = observable({
count: 0,
increment() {
this.count++;
}
});
autorun(() => {
console.log(`Count: ${appState.count}`);
});
appState.increment(); // Count: 1
appState.increment(); // Count: 2
const Counter = observer(() => (
<div>
<p>Count: {appState.count}</p>
<button onClick={() => appState.increment()}>Increment</button>
</div>
));
ReactDOM.render(<Counter />, document.getElementById('root'));
const handler = {
set(target, property, value) {
console.log(`Setting value of ${property} to ${value}`);
target[property] = value;
document.getElementById(property).innerText = value;
return true;
}
};
const state = {
count: 0
};
const proxyState = new Proxy(state, handler);
document.getElementById('increment').addEventListener('click', () => {
proxyState.count++;
});
<div>
<p id="count">0</p>
<button id="increment">Increment</button>
</div>
<script src="path/to/your/script.js"></script>
28 Dec, 16:10
28 Dec, 09:10
[]
.let propName = 'name';
let person = {
[propName]: 'Alice'
};
console.log(person.name); // 'Alice'
let key = 'age';
let person = {
name: 'Alice',
[key]: 25
};
console.log(person.name); // 'Alice'
console.log(person.age); // 25
let i = 0;
let obj = {
['prop_' + ++i]: i,
['prop_' + ++i]: i,
['prop_' + ++i]: i
};
console.log(obj); // { prop_1: 1, prop_2: 2, prop_3: 3 }
let prefix = 'user';
let index = 1;
let users = {
[prefix + index]: { name: 'Alice' },
[prefix + (index + 1)]: { name: 'Bob' }
};
console.log(users.user1.name); // 'Alice'
console.log(users.user2.name); // 'Bob'
function createKey(base, index) {
return base + index;
}
let obj = {
[createKey('key', 1)]: 'value1',
[createKey('key', 2)]: 'value2'
};
console.log(obj.key1); // 'value1'
console.log(obj.key2); // 'value2'
let studentName1 = 'Alice';
let studentName2 = 'Bob';
let grades = {
[studentName1]: 85,
[studentName2]: 92
};
console.log(grades.Alice); // 85
console.log(grades.Bob); // 92
function getFilterKey(filterName) {
return `filter_${filterName}`;
}
let filters = {};
filters[getFilterKey('age')] = 25;
filters[getFilterKey('location')] = 'New York';
console.log(filters); // { filter_age: 25, filter_location: 'New York' }
27 Dec, 16:10
27 Dec, 09:10
type
, указывающее тип экшна. Дополнительно могут быть добавлены другие свойства для передачи данных.const incrementAction = {
type: 'INCREMENT'
};
const addTodoAction = {
type: 'ADD_TODO',
payload: {
id: 1,
text: 'Learn Redux'
}
};
const increment = () => {
return {
type: 'INCREMENT'
};
};
const addTodo = (id, text) => {
return {
type: 'ADD_TODO',
payload: {
id,
text
}
};
};
const initialState = {
count: 0,
todos: []
};
const rootReducer = (state = initialState, action) => {
switch (action.type) {
case 'INCREMENT':
return {
...state,
count: state.count + 1
};
case 'ADD_TODO':
return {
...state,
todos: [...state.todos, action.payload]
};
default:
return state;
}
};
npm install redux react-redux
import { createStore } from 'redux';
import rootReducer from './reducers';
const store = createStore(rootReducer);
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import App from './App';
import store from './store';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
const incrementAction = { type: 'INCREMENT' };
const addTodoAction = {
type: 'ADD_TODO',
payload: { id: 1, text: 'Learn Redux' }
};
const increment = () => ({ type: 'INCREMENT' });
const addTodo = (id, text) => ({
type: 'ADD_TODO',
payload: { id, text }
});
const rootReducer = (state = initialState, action) => {
switch (action.type) {
case 'INCREMENT':
return { ...state, count: state.count + 1 };
case 'ADD_TODO':
return { ...state, todos: [...state.todos, action.payload] };
default:
return state;
}
};
26 Dec, 16:10
26 Dec, 09:10
state
) action
)const reducer = (state, action) => {
switch (action.type) {
case 'ACTION_TYPE':
// Возвращаем новое состояние
return {
...state,
// Обновляем определенные свойства
};
default:
return state;
}
};
const initialState = {
count: 0
};
const counterReducer = (state = initialState, action) => {
switch (action.type) {
case 'INCREMENT':
return {
...state,
count: state.count + 1
};
case 'DECREMENT':
return {
...state,
count: state.count - 1
};
default:
return state;
}
};
useReducer
для управления состоянием с помощью редьюсера в функциональных компонентах.import React, { useReducer } from 'react';
const initialState = { count: 0 };
const counterReducer = (state, action) => {
switch (action.type) {
case 'INCREMENT':
return { count: state.count + 1 };
case 'DECREMENT':
return { count: state.count - 1 };
default:
return state;
}
};
const Counter = () => {
const [state, dispatch] = useReducer(counterReducer, initialState);
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: 'INCREMENT' })}>Increment</button>
<button onClick={() => dispatch({ type: 'DECREMENT' })}>Decrement</button>
</div>
);
};
export default Counter;
25 Dec, 09:10
useEffect
. Когда компонент демонтируется, React вызывает функцию очистки, которую можно определить внутри useEffect
.useEffect
позволяет выполнять побочные эффекты в функциональных компонентах. Функция очистки, возвращаемая из useEffect
, выполняется при демонтировании компонента.import React, { useEffect } from 'react';
const MyComponent = () => {
useEffect(() => {
console.log('Component mounted');
// Функция очистки вызывается при демонтировании компонента
return () => {
console.log('Component will unmount');
};
}, []); // Пустой массив зависимостей означает, что эффект выполнится только при монтировании и демонтировании
return (
<div>
<p>My Component</p>
</div>
);
};
export default MyComponent;
useEffect
useEffect(() => {
console.log('Component mounted');
return () => {
console.log('Component will unmount');
};
}, []);
import React, { useEffect, useState } from 'react';
const WebSocketComponent = () => {
const [messages, setMessages] = useState([]);
useEffect(() => {
const socket = new WebSocket('ws://example.com/socket');
socket.onmessage = (event) => {
setMessages((prevMessages) => [...prevMessages, event.data]);
};
console.log('WebSocket connection opened');
return () => {
socket.close();
console.log('WebSocket connection closed');
};
}, []);
return (
<div>
<h1>WebSocket Messages</h1>
<ul>
{messages.map((message, index) => (
<li key={index}>{message}</li>
))}
</ul>
</div>
);
};
export default WebSocketComponent;
const socket = new WebSocket('ws://example.com/socket');
socket.onmessage = (event) => {
setMessages((prevMessages) => [...prevMessages, event.data]);
};
return () => {
socket.close();
console.log('WebSocket connection closed');
};
24 Dec, 16:10
24 Dec, 09:10
useState
позволяет добавить состояние в функциональный компонент.import React, { useState } from 'react';
const Counter = () => {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};
export default Counter;
useContext
позволяет использовать контекст для передачи данных через дерево компонентов без необходимости передавать пропсы на промежуточных уровнях.import React, { useContext } from 'react';
const ThemeContext = React.createContext('light');
const ThemedComponent = () => {
const theme = useContext(ThemeContext);
return <div style={{ background: theme === 'light' ? '#fff' : '#333', color: theme === 'light' ? '#000' : '#fff' }}>
The current theme is {theme}
</div>;
};
const App = () => {
return (
<ThemeContext.Provider value="dark">
<ThemedComponent />
</ThemeContext.Provider>
);
};
export default App;
useReducer
— это альтернатива useState
для управления более сложным состоянием в компоненте.import React, { useReducer } from 'react';
const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
throw new Error();
}
}
const Counter = () => {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: 'increment' })}>Increment</button>
<button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button>
</div>
);
};
export default Counter;
useRef
возвращает изменяемый объект-реф, который сохраняется при повторных рендерах компонента. Это часто используется для доступа к DOM-элементам или для сохранения переменных, которые не вызывают повторный рендер при изменении.import React, { useRef } from 'react';
const TextInputWithFocusButton = () => {
const inputEl = useRef(null);
const onButtonClick = () => {
// "current" указывает на смонтированный элемент input
inputEl.current.focus();
};
return (
<div>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</div>
);
};
export default TextInputWithFocusButton;
23 Dec, 16:10
23 Dec, 09:10
import React, { useState } from 'react';
const ControlledComponent = () => {
const [inputValue, setInputValue] = useState('');
const handleChange = (event) => {
setInputValue(event.target.value);
};
return (
<div>
<label>
Name:
<input type="text" value={inputValue} onChange={handleChange} />
</label>
<p>Current value: {inputValue}</p>
</div>
);
};
export default ControlledComponent;
onChange
) и обновляют состояние компонента.import React, { useRef } from 'react';
const UncontrolledComponent = () => {
const inputRef = useRef(null);
const handleSubmit = (event) => {
event.preventDefault();
alert('Submitted value: ' + inputRef.current.value);
};
return (
<form onSubmit={handleSubmit}>
<label>
Name:
<input type="text" ref={inputRef} />
</label>
<button type="submit">Submit</button>
</form>
);
};
export default UncontrolledComponent;
useRef
).22 Dec, 16:10
22 Dec, 09:10
map()
, который позволяет перебрать массив и вернуть JSX для каждого элемента. Это удобный и декларативный способ создания списков элементов.import React from 'react';
const users = [
{ id: 1, name: 'Alice', age: 25 },
{ id: 2, name: 'Bob', age: 30 },
{ id: 3, name: 'Charlie', age: 35 }
];
const UserList = () => {
return (
<div>
<h1>User List</h1>
<ul>
{users.map(user => (
<li key={user.id}>
{user.name} - {user.age} years old
</li>
))}
</ul>
</div>
);
};
export default UserList;
map()
{users.map(user => (
<li key={user.id}>
{user.name} - {user.age} years old
</li>
))}
key
<li key={user.id}>
map()
.import React from 'react';
const users = [
{ id: 1, name: 'Alice', age: 25, email: '[email protected]' },
{ id: 2, name: 'Bob', age: 30, email: '[email protected]' },
{ id: 3, name: 'Charlie', age: 35, email: '[email protected]' }
];
const UserItem = ({ user }) => {
return (
<div className="user-item">
<h2>{user.name}</h2>
<p>Age: {user.age}</p>
<p>Email: {user.email}</p>
</div>
);
};
const UserList = () => {
return (
<div>
<h1>User List</h1>
{users.map(user => (
<UserItem key={user.id} user={user} />
))}
</div>
);
};
export default UserList;
const UserItem = ({ user }) => {
return (
<div className="user-item">
<h2>{user.name}</h2>
<p>Age: {user.age}</p>
<p>Email: {user.email}</p>
</div>
);
};
map()
{users.map(user => (
<UserItem key={user.id} user={user} />
))}
21 Dec, 16:10