- Хук может заменить методы жизненного цикла классовых компонентов для выполнения кода после каждого рендеринга.
- Принимает функцию эффекта и массив зависимостей, указывая, при изменении каких пропсов или состояний должен выполняться эффект.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍25🔥4❤2
Это шаблон в React, который позволяет повторно использовать логику компонентов. HOC — это функция, которая принимает компонент и возвращает новый компонент с добавленной функциональностью.
HOC позволяет разделять и повторно использовать логику между разными компонентами, не дублируя код.
HOC помогает создавать более абстрактные и композиционные компоненты, что улучшает архитектуру приложения.
HOC позволяет разделять обязанности между различными компонентами, улучшая структуру и читаемость кода.
HOC создается как функция, которая принимает компонент и возвращает новый компонент с добавленной функциональностью.
В этом примере
withLogging
— это функция, которая принимает компонент WrappedComponent
и возвращает новый компонент, оборачивающий WrappedComponent
с добавленной логикой логирования.import React, { Component } from 'react';
// Функция, создающая HOC
function withLogging(WrappedComponent) {
return class extends Component {
componentDidMount() {
console.log(`Компонент ${WrappedComponent.name} был смонтирован`);
}
componentWillUnmount() {
console.log(`Компонент ${WrappedComponent.name} будет размонтирован`);
}
render() {
// Передача пропсов в обёрнутый компонент
return <WrappedComponent {...this.props} />;
}
};
}
// Пример использования HOC
class MyComponent extends Component {
render() {
return <div>Привет, мир!</div>;
}
}
const MyComponentWithLogging = withLogging(MyComponent);
export default MyComponentWithLogging;
HOC может использоваться для оборачивания компонента логикой загрузки данных из API или управления состоянием данных.
HOC может использоваться для управления доступом к компонентам, проверяя права пользователя и условно рендеря компоненты.
HOC может добавлять общие методы или состояние, которое нужно разделить между несколькими компонентами.
В этом примере
withAuthorization
проверяет роль пользователя и условно рендерит WrappedComponent
, если пользователь имеет соответствующую роль, или показывает сообщение о запрете доступа.import React from 'react';
// Функция, создающая HOC для проверки прав доступа
function withAuthorization(WrappedComponent, userRole) {
return class extends React.Component {
render() {
const { role } = this.props;
if (role !== userRole) {
return <div>Доступ запрещен</div>;
}
return <WrappedComponent {...this.props} />;
}
};
}
// Пример использования HOC
class AdminPanel extends React.Component {
render() {
return <div>Панель администратора</div>;
}
}
const AdminPanelWithAuthorization = withAuthorization(AdminPanel, 'admin');
export default AdminPanelWithAuthorization;
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14❤1
- DOM позволяет программам читать и изменять документ структурно, стилистически и содержательно, реагируя на пользовательские взаимодействия.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍24🔥4❤1
Начальное состояние, не завершённое или отклонённое.
Операция завершена успешно.
Операция завершена с ошибкой.
Промис создаётся с использованием конструктора
Promise
, который принимает функцию с двумя аргументами: resolve
и reject
. Эти аргументы являются функциями, которые изменяют состояние промиса.const myPromise = new Promise((resolve, reject) => {
// Асинхронная операция
setTimeout(() => {
const success = true;
if (success) {
resolve('Операция успешно завершена');
} else {
reject('Произошла ошибка');
}
}, 1000);
});
Промисы имеют несколько методов, которые позволяют работать с результатом асинхронной операции.
Метод
then
используется для обработки успешного выполнения промиса (состояние Fulfilled). Он принимает два аргумента: первый — функция для обработки успешного результата, второй — функция для обработки ошибки (необязательный).myPromise.then(result => {
console.log(result); // 'Операция успешно завершена'
}).catch(error => {
console.error(error);
});
Метод
catch
используется для обработки отклонённого промиса (состояние Rejected). Он принимает функцию, которая будет вызвана при ошибке.myPromise.catch(error => {
console.error(error); // 'Произошла ошибка'
});
Метод
finally
выполняется после завершения промиса, независимо от того, был он исполнен или отклонён. Он полезен для выполнения кода, который должен быть выполнен в любом случае (например, очистка ресурсов).myPromise.finally(() => {
console.log('Промис завершён'); // Выполняется в любом случае
});
Методы
then
и catch
возвращают новые промисы, что позволяет создавать цепочки асинхронных операций.myPromise
.then(result => {
console.log(result); // 'Операция успешно завершена'
return 'Следующий результат';
})
.then(nextResult => {
console.log(nextResult); // 'Следующий результат'
})
.catch(error => {
console.error(error); // Обработка ошибок для всех предыдущих промисов
});
function fetchData(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.onload = () => {
if (xhr.status === 200) {
resolve(JSON.parse(xhr.responseText));
} else {
reject(`Ошибка: ${xhr.status}`);
}
};
xhr.onerror = () => reject('Ошибка сети');
xhr.send();
});
}
fetchData('https://api.example.com/data')
.then(data => {
console.log('Данные получены:', data);
})
.catch(error => {
console.error('Ошибка получения данных:', error);
});
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍35
2. Переназначение: Переменные, объявленные с помощью `let`, могут быть переназначены, т.е. вы можете изменить значение переменной позже в коде.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍28🔥1
Forwarded from Идущий к IT
Твое резюме на HeadHunter — ОК, если ты видишь это.
HeadHunter сравнивает ключевые навыки в твоем резюме и в вакансии и в момент отклика отображает, насколько % ты соответствуешь требованиям.
Специальный бейджик «Подходит по навыкам на 100%» отображается, если соответствие составляет более 60%.
Если при просмотре вакансий ты видишь такой бейджик, это значит, что список навыков в твоем резюме качественно составлен.
Это важный параметр, так как рекрутерам чаще показываются резюме с лучшим соответствием.
О том, как правильно указывать ключевые навыки и оптимизировать свое резюме я уже рассказывал в этом видео
HeadHunter сравнивает ключевые навыки в твоем резюме и в вакансии и в момент отклика отображает, насколько % ты соответствуешь требованиям.
Специальный бейджик «Подходит по навыкам на 100%» отображается, если соответствие составляет более 60%.
Если при просмотре вакансий ты видишь такой бейджик, это значит, что список навыков в твоем резюме качественно составлен.
Это важный параметр, так как рекрутерам чаще показываются резюме с лучшим соответствием.
О том, как правильно указывать ключевые навыки и оптимизировать свое резюме я уже рассказывал в этом видео
👍2
Для обработки значений формы в Vuex (состоянии управления в приложениях Vue) нужно выполнить следующие шаги:
Создайте компонент с формой, который будет использоваться для ввода данных.
<template>
<div>
<form @submit.prevent="handleSubmit">
<label for="name">Имя:</label>
<input type="text" id="name" v-model="name" />
<label for="email">Email:</label>
<input type="email" id="email" v-model="email" />
<button type="submit">Отправить</button>
</form>
</div>
</template>
<script>
export default {
data() {
return {
name: '',
email: ''
};
},
methods: {
handleSubmit() {
this.$store.dispatch('submitForm', {
name: this.name,
email: this.email
});
}
}
};
</script>
Создайте состояние для хранения данных формы, мутации для обновления состояния и действия для обработки отправки формы.
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
formData: {
name: '',
email: ''
}
},
mutations: {
SET_FORM_DATA(state, payload) {
state.formData = payload;
}
},
actions: {
submitForm({ commit }, formData) {
// Здесь вы можете выполнить любые асинхронные операции, такие как отправка данных на сервер
// Например, с использованием axios:
// axios.post('/api/form', formData).then(response => {
// console.log(response.data);
// });
commit('SET_FORM_DATA', formData);
}
}
});
Вы можете использовать
mapState
и mapMutations
для связывания состояния и мутаций Vuex с вашим компонентом.<template>
<div>
<form @submit.prevent="handleSubmit">
<label for="name">Имя:</label>
<input type="text" id="name" v-model="localName" />
<label for="email">Email:</label>
<input type="email" id="email" v-model="localEmail" />
<button type="submit">Отправить</button>
</form>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex';
export default {
computed: {
...mapState({
name: state => state.formData.name,
email: state => state.formData.email
}),
localName: {
get() {
return this.name;
},
set(value) {
this.updateForm({ name: value, email: this.email });
}
},
localEmail: {
get() {
return this.email;
},
set(value) {
this.updateForm({ name: this.name, email: value });
}
}
},
methods: {
...mapActions(['submitForm']),
handleSubmit() {
this.submitForm({
name: this.localName,
email: this.localEmail
});
},
updateForm(payload) {
this.$store.commit('SET_FORM_DATA', payload);
}
}
};
</script>
Когда пользователь отправляет форму, данные формы отправляются в Vuex с помощью действия
submitForm
, которое обновляет состояние через мутацию SET_FORM_DATA
.Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
❤21👍15
Который является официальной библиотекой для управления состоянием в приложениях Vue.js,
mutations
(мутации) и actions
(действия) играют ключевые роли в управлении состоянием. Они помогают обеспечивать предсказуемость изменения состояния и организовывают логику приложения.Это единственный способ изменить состояние в 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;
}
}
});
Действия используются для выполнения асинхронных операций или сложной бизнес-логики перед вызовом мутаций. Действия могут содержать произвольную асинхронную логику, такие как 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);
}
}
});
Синхронно изменяют состояние.
Могут быть асинхронными и обычно вызывают мутации для изменения состояния.
Пример взаимодействия
// 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>
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍19🔥6
Это протокол коммуникации, предоставляющий двусторонний, полнодуплексный канал связи между клиентом и сервером через одно соединение TCP. Он позволяет обмениваться данными в режиме реального времени, что делает его идеальным для приложений, требующих мгновенной передачи информации, таких как чаты, игры, финансовые системы и другие.
WebSockets обеспечивают полнодуплексное общение, позволяя серверу и клиенту отправлять данные друг другу в любое время.
В отличие от HTTP, где каждое запрос-ответное взаимодействие открывает и закрывает соединение, WebSocket поддерживает постоянное соединение, что позволяет мгновенно передавать данные.
WebSockets уменьшают накладные расходы на установление соединений и протоколирование запросов, что приводит к более низкой задержке и уменьшенному использованию ресурсов по сравнению с регулярными HTTP-запросами.
WebSockets поддерживают передачу не только текстовых данных, но и бинарных, что расширяет возможности их применения.
Соединение WebSocket начинается с "рукопожатия" по протоколу HTTP. Клиент отправляет запрос на установление соединения с сервером, используя заголовок
Upgrade
, чтобы переключиться с HTTP на WebSocket.Если сервер принимает запрос, он отвечает с подтверждением, и соединение переключается на протокол WebSocket. С этого момента канал связи открыт и доступен для двусторонней передачи данных.
Клиент и сервер могут обмениваться данными в любом направлении. Сообщения отправляются в рамках установленного соединения без необходимости повторного рукопожатия.
Соединение может быть закрыто любой стороной (клиентом или сервером) в любое время. Это может быть сделано по желанию или в случае ошибки.
const WebSocket = require('ws');
const server = new WebSocket.Server({ port: 8080 });
server.on('connection', (socket) => {
console.log('Client connected');
socket.on('message', (message) => {
console.log(`Received: ${message}`);
socket.send(`You said: ${message}`);
});
socket.on('close', () => {
console.log('Client disconnected');
});
});
console.log('WebSocket server is running on ws://localhost:8080');
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍36❤1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13👍6❤1
Это техника, используемая для реализации связи между клиентом и сервером в веб-приложениях, чтобы поддерживать обновление данных в реальном времени. В отличие от обычных HTTP-запросов, лонг-пулинг позволяет клиенту ждать ответа от сервера дольше, что помогает уменьшить задержку при получении новых данных.
Клиент отправляет HTTP-запрос к серверу.
Сервер не отвечает сразу, а задерживает ответ до тех пор, пока не появятся новые данные или не истечет таймаут.
Когда данные становятся доступными или истекает таймаут ожидания, сервер отправляет ответ клиенту.
Клиент обрабатывает полученные данные и немедленно отправляет новый запрос к серверу для получения следующих обновлений.
Сервер на Node.js с использованием
express
const express = require('express');
const app = express();
let messages = [];
let clients = [];
// Endpoint для отправки сообщений
app.post('/messages', (req, res) => {
const message = req.body.message;
messages.push(message);
// Уведомляем всех клиентов
clients.forEach(client => client.res.json({ message }));
clients = [];
res.status(200).send('Message sent');
});
// Endpoint для получения сообщений (лонг-пулинг)
app.get('/messages', (req, res) => {
if (messages.length > 0) {
res.json({ message: messages.pop() });
} else {
clients.push({ req, res });
}
});
app.listen(3000, () => {
console.log('Server listening on port 3000');
});
Клиентский код на JavaScript
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Long Polling Example</title>
</head>
<body>
<h1>Long Polling Example</h1>
<div id="messages"></div>
<script>
function pollMessages() {
fetch('/messages')
.then(response => response.json())
.then(data => {
const messageDiv = document.createElement('div');
messageDiv.textContent = `New message: ${data.message}`;
document.getElementById('messages').appendChild(messageDiv);
pollMessages(); // Отправляем новый запрос после получения сообщения
})
.catch(error => {
console.error('Error:', error);
setTimeout(pollMessages, 5000); // Повторный запрос через 5 секунд при ошибке
});
}
// Начинаем лонг-пулинг
pollMessages();
</script>
</body>
</html>
Лонг-пулинг позволяет получать данные в реальном времени без необходимости постоянно проверять сервер с частыми запросами.
По сравнению с обычным пулингом (когда клиент постоянно отправляет запросы с фиксированным интервалом), лонг-пулинг уменьшает количество HTTP-запросов, что снижает нагрузку на сервер.
Лонг-пулинг легче внедрить и поддерживать в сравнении с более сложными технологиями, такими как WebSockets.
Хотя лонг-пулинг уменьшает задержку по сравнению с обычным пулингом, он все же может иметь небольшие задержки в зависимости от времени ожидания и частоты событий.
Держание соединений открытыми в течение длительного времени может быть ресурсоемким для сервера, особенно при большом количестве клиентов.
Лонг-пулинг менее эффективен по сравнению с WebSockets, которые предоставляют постоянное двустороннее соединение.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10❤5🔥3😁2
State manager — это инструмент или библиотека для управления состоянием приложения, особенно в сложных проектах с большим количеством взаимозависимых данных. Популярные state manager’ы включают Redux, MobX и Zustand для React-приложений, обеспечивающие централизованное хранение и управление состоянием. Они помогают структурировать данные, отслеживать их изменения и синхронизировать их между компонентами.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍22🔥8❤1
Это процесс проверки подлинности пользователя, который пытается получить доступ к системе или ресурсу. Веб-приложения и сервисы обычно используют несколько методов аутентификации для обеспечения безопасности и защиты данных.
Пользователь вводит имя пользователя и пароль, которые проверяются на сервере. Веб-сайты с формой входа, требующей логин и пароль.
После успешного входа пользователь получает токен (например, JWT), который используется для дальнейших запросов. API, использующие токены для проверки подлинности запросов.
Протокол авторизации, позволяющий сторонним приложениям получать ограниченный доступ к ресурсам пользователя без передачи пароля. Вход через Google, Facebook или другие социальные сети.
Требует два различных типа проверки (например, пароль и одноразовый код). Вход с использованием пароля и SMS-кода.
Использует биометрические данные (например, отпечатки пальцев или распознавание лиц) для проверки подлинности. Вход через Touch ID или Face ID на мобильных устройствах.
npm install express jsonwebtoken bcryptjs body-parser
const express = require('express');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const bodyParser = require('body-parser');
const app = express();
const PORT = 3000;
const SECRET_KEY = 'your_secret_key';
let users = []; // Для простоты используем массив в памяти
app.use(bodyParser.json());
// Регистрация пользователя
app.post('/register', async (req, res) => {
const { username, password } = req.body;
const hashedPassword = await bcrypt.hash(password, 8);
users.push({ username, password: hashedPassword });
res.status(201).send('User registered');
});
// Вход пользователя
app.post('/login', async (req, res) => {
const { username, password } = req.body;
const user = users.find(u => u.username === username);
if (!user) {
return res.status(404).send('User not found');
}
const isPasswordValid = await bcrypt.compare(password, user.password);
if (!isPasswordValid) {
return res.status(401).send('Invalid password');
}
const token = jwt.sign({ username: user.username }, SECRET_KEY, { expiresIn: '1h' });
res.json({ token });
});
// Защищенный маршрут
app.get('/protected', (req, res) => {
const token = req.headers['authorization'];
if (!token) {
return res.status(401).send('Access denied');
}
try {
const decoded = jwt.verify(token, SECRET_KEY);
res.json({ message: 'Protected content', user: decoded });
} catch (err) {
res.status(401).send('Invalid token');
}
});
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍32🔥3
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍27🔥3
GET-запросы отправляют данные через URL, который сохраняется в истории браузера. Это означает, что любой, кто имеет доступ к истории браузера, может увидеть эти данные.
Многие веб-серверы и прокси-серверы автоматически записывают URL всех запросов в свои логи. Чувствительная информация в URL будет сохранена в этих логах и может быть доступна администраторам серверов или в случае компрометации системы.
Браузеры, прокси-серверы и промежуточные серверы могут кэшировать URL-адреса GET-запросов. Это означает, что чувствительная информация может быть сохранена в кэшах и доступна при последующих обращениях.
Большинство браузеров и серверов имеют ограничения на длину URL (обычно около 2000 символов). Если данные слишком длинные, они могут быть обрезаны, что приведет к потере информации или ошибкам при обработке запроса.
Когда пользователь переходит по ссылке с одной страницы на другую, URL-адрес исходной страницы часто передается как заголовок Referer в HTTP-запросе. Это означает, что чувствительная информация в URL может быть передана сторонним сайтам.
Данные в GET-запросах передаются через URL, в то время как данные в POST-запросах передаются в теле запроса. URL более подвержены утечке, так как они часто видны в различных местах (например, в журналах серверов, истории браузера и т.д.).
Для отправки чувствительной информации лучше использовать POST-запросы, так как данные передаются в теле запроса и не сохраняются в URL.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Secure Form</title>
</head>
<body>
<form action="/submit" method="post">
<label for="username">Username:</label>
<input type="text" id="username" name="username">
<label for="password">Password:</label>
<input type="password" id="password" name="password">
<button type="submit">Submit</button>
</form>
</body>
</html>
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍25
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍26❤2🔥1
Это мера, которая оценивает сложность структуры и конструкции кода. Она часто используется для оценки понятности, поддерживаемости и вероятности ошибок в программном коде. Одним из наиболее известных методов измерения синтаксической сложности является цикломатическая сложность, предложенная Томасом Маккейбом в 1976 году.
Это количественная мера количества независимых путей через программу. Она используется для оценки сложности программного кода, измеряя количество логических ветвлений. Чем выше цикломатическая сложность, тем больше возможных путей исполнения и, следовательно, тем сложнее понять и протестировать программу.
Цикломатическая сложность может быть рассчитана с помощью следующей формулы:
V(G) = E - N + 2P
def example(a, b):
if a > 0:
if b > 0:
return a + b
else:
return a - b
else:
return b
Цикломатическая сложность
V(G)
будетV(G) = E - N + 2P
V(G) = 6 - 5 + 2*1
V(G) = 3
Чем выше сложность, тем труднее понять код. Программы с высокой сложностью требуют больше времени для анализа и понимания.
Код с высокой сложностью сложнее поддерживать и изменять. Это может привести к большему числу ошибок при внесении изменений.
Более сложный код требует большего количества тестов для покрытия всех возможных путей исполнения. Это увеличивает время и усилия, необходимые для тестирования.
Программы с низкой сложностью, как правило, более надежны и менее подвержены ошибкам, так как легче понимать и тестировать все возможные сценарии.
Разделение сложных функций на более простые и малые функции. Использование более простых и понятных конструкций.
Вынос повторяющегося кода в отдельные функции или методы.
Добавление пояснительных комментариев и документации для сложных участков кода.
Использование проверенных паттернов проектирования для упрощения и структурирования кода.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17❤1
Каждый элемент, атрибут или текстовый узел страницы представлен как узел дерева, что позволяет программам (например, через JavaScript) взаимодействовать с документом, изменять его содержимое и структуру.
DOM-дерево обеспечивает удобный способ управления элементами веб-страницы динамически.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍34🔥7❤1🤯1