Точка входа в программирование
20.3K subscribers
1.25K photos
216 videos
2 files
2.77K links
Фундаментальные знания по основам программирования

Разместить рекламу: @tproger_sales_bot

Правила общения: https://tprg.ru/rules

Другие каналы: @tproger_channels

Сайт: https://tprg.ru/site

Регистрация в перечне РКН: https://tprg.ru/zrgj
Download Telegram
#простымисловами: Паттерн Observer (Наблюдатель)

Observer отлично подходит для систем, где есть необходимость в автоматическом уведомлении об изменениях. Однако его следует использовать вдумчиво, чтобы избежать излишнего усложнения логики. Паттерн помогает создать динамичные и масштабируемые приложения, такие как системы уведомлений, финансовые инструменты или игровые события.

Подробнее в карточках.
👍81🔥1
Что такое стек и куча?

Стек — это область памяти, где хранятся временные данные, например, локальные переменные и параметры функций. Он работает по принципу «последним пришёл — первым ушёл". Когда функция завершается, её данные автоматически удаляются. Стек быстрый, но его размер ограничен.

Куча — это область памяти для данных, которые живут долго, например, объекты или массивы. Данные в куче выделяются вручную или автоматически (например, с помощью сборщика мусора). Она гибче стека, но доступ к ней медленнее.

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

def add(a, b):
result = a + b # Локальные переменные хранятся в стеке
return result



Пример использования кучи:

class User:
def __init__(self, name):
self.name = name # Объект "User" хранится в куче

user = User("Alex")
print(user.name)


Стек используется для временных данных, куча — для долгоживущих объектов. Знание этих областей памяти помогает оптимизировать программы и избегать утечек памяти.

#простымисловами #основы
🔥811
Как работают хэш-функции

Хэш-функция — это алгоритм, который принимает произвольные данные (например, строку или файл) и преобразует их в фиксированную строку определенной длины, называемую хэш-значением.
Два ключевых свойства:

1. Для одного и того же ввода всегда возвращается одинаковый хэш.
2. Невозможно восстановить исходные данные по хэшу (обратное преобразование).

Давайте рассмотрим пример

Возьмём строку "password123" и пропустим её через хэш-функцию (например, SHA-256). Она вернёт хэш-значение:
password123 → ef92b778bae11c00c8cc0d9525c7f90631ad9e11cdec095c9c3af7b06ecf90fc


Хэш будет одинаковым для "password123", сколько бы раз вы его ни рассчитывали. Но если изменить хотя бы один символ, хэш станет совершенно другим.

Пример кода на Python

import hashlib

# Пример строки
text = "password123"

# Использование SHA-256 для получения хэша
hash_object = hashlib.sha256(text.encode())
hash_value = hash_object.hexdigest()

print("Хэш:", hash_value)


Результат: ef92b778bae11c00c8cc0d9525c7f90631ad9e11cdec095c9c3af7b06ecf90fc

Где используется:

1. Для хранения паролей: Вместо хранения пароля "password123" его хэш сохраняют в базе данных. Когда пользователь вводит пароль, хэш снова рассчитывается и сравнивается с сохранённым хэшем.

2. Для ускорения поиска данных: Например, в хэш-таблицах (словарях Python). При добавлении ключа "text" его хэш помогает найти место для хранения значения.

3. В хэш-таблицах: Структура данных для хранения пар «ключ-значение». Хэш-функция вычисляет индекс, где хранится значение, что ускоряет доступ к данным.

#простымисловами
👍11
Зачем нужны контейнеры в программировании

Контейнеры, такие как Docker, нужны, чтобы создавать лёгкие и изолированные окружения для запуска приложений. Проще говоря, это как коробка, в которую вы кладёте ваше приложение вместе со всем, что ему нужно для работы (например, библиотеки, зависимости, настройки), а потом можете запустить эту коробку где угодно.

Зачем это нужно?

1. «Работает у меня». У вас есть приложение, которое отлично работает на вашей машине. Но на сервере оно не запускается из-за разных версий библиотек или зависимостей. С контейнером такие проблемы исчезают, потому что всё, что нужно приложению, идёт с ним в одном «пакете».

2. Универсальная упаковка. Контейнеры работают одинаково на любом компьютере или сервере, будь то ваш ноутбук, облако или чужая инфраструктура. Это экономит время и нервы.

3. Изоляция. Каждый контейнер полностью изолирован. Если в одном контейнере что-то сломалось или идёт нагрузка, это не повлияет на другие.

Пример из реальной жизни

Представьте, что вы повар и вам нужно приготовить блюдо в чужой кухне. Но в чужой кухне может не быть нужных продуктов, посуды и приборов. Контейнер — это коробка, в которой вы привозите всё, что вам нужно: продукты, кастрюли, специи. Теперь вы можете готовить это блюдо в любой кухне, не беспокоясь о том, что чего-то будет не хватать.

Где это используется?

В разработке: программисты создают контейнер с приложением, и каждый в команде может работать в одинаковых условиях.

В тестировании: легко запускать копии приложения с разными настройками для проверки.

В продакшене: легко развернуть приложение на реальном сервере без сюрпризов.

#простымисловами
🔥11👍3
Что такое асинхронность

Сперва немного терминологии. Асинхронность — это способность программы выполнять несколько задач одновременно, не дожидаясь завершения каждого шага. Это особенно полезно, когда программа выполняет долгие операции (например, загрузку данных из сети), но при этом не блокирует выполнение других задач.

Если код работает синхронно, каждая операция выполняется строго по порядку. Это может привести к задержкам:

import time

print("Загрузка данных...")
time.sleep(5) # Программа засыпает на 5 секунд
print("Данные загружены!")


В примере выше всё остальное в программе «заморожено», пока выполняется sleep(). Если бы это была веб-страница, она зависла бы на несколько секунд.

Как работают async/await

В асинхронном программировании код выполняется без блокировки. Программа продолжает работать, пока выполняются долгие задачи.

Пример на Python с asyncio:

import asyncio

async def загрузка_данных():
print("Загрузка данных...")
await asyncio.sleep(5) # Не блокирует программу
print("Данные загружены!")

async def main():
await загрузка_данных()

asyncio.run(main())


Давайте разберёмся, что здесь происходит:

1. async делает функцию асинхронной.
2. await говорит «подожди, но не блокируй остальную программу».
3. asyncio.run(main()) запускает асинхронную операцию.

Асинхронность делает код быстрее и эффективнее, особенно при работе с долго выполняющимися операциями!

#простымисловами #основы
👍11
Forwarded from Веб-страница
Как правильно работать с DOM в JavaScript в 2025 году?

Работа с DOM (Document Object Model) — это основа веб-разработки. С каждым годом появляются новые, более эффективные способы манипуляции элементами страницы. Давайте разберём, как сегодня правильно работать с DOM в JavaScript, чтобы код был быстрым, удобным и безопасным.

1. Получение элементов

Вместо старых getElementById и getElementsByClassName сегодня лучше использовать querySelector и querySelectorAll. Они более универсальные и понятные.

const title = document.querySelector("#title"); // Получает 1 элемент (по id)
const buttons = document.querySelectorAll(".btn"); // Получает список всех кнопок с классом .btn


querySelector и querySelectorAll позволяют находить элементы так же, как в CSS (.класс, #id, input[type="text"] и т. д.). А также querySelectorAll возвращает не «живую» коллекцию, а обычный статичный список (NodeList), что логичнее при итерации.

2. Изменение текста и HTML

Всё зависит от того, что именно нужно поменять.

textContent — если надо изменить только текст (без HTML).

title.textContent = "Привет, мир!";


Не используйте innerHTML, если вставляете данные от пользователя — это дыра в безопасности (XSS-атаки). Если всё же используется innerHTML, убедитесь, что данные проверены.

title.innerHTML = "<strong>Важное сообщение!</strong>";


insertAdjacentHTML — отличная альтернатива innerHTML, если нужно добавить HTML в определённое место, не перезаписывая весь элемент.

title.insertAdjacentHTML("beforeend", "<span> 👋</span>");


3. Изменение классов

Правильный способ через classList, потому что `className`заменяет все классы сразу, из-за чего можно случайно удалить важные стили.

title.classList.add("highlight"); // Добавит класс
title.classList.remove("hidden"); // Удалит класс
title.classList.toggle("active"); // Переключит класс (если был — уберёт, если не было — добавит)


4. Изменение стилей

Не стоит вручную писать style.cssText, потому что он затирает всё, что было до этого. Используйте style для отдельных свойств.

title.style.color = "red";
title.style.fontSize = "24px";


Если нужно много стилей — лучше добавьте или измените класс. Так проще, централизованно и удобнее управлять дизайном.

title.classList.add("error"); // В CSS заранее определите .error { color: red; }


5. Создание и добавление новых элементов

Лучший способ — использовать createElement, а не innerHTML.

const newDiv = document.createElement("div"); // Создаём элемент <div>
newDiv.textContent = "Новый блок!";
newDiv.classList.add("box");
document.body.appendChild(newDiv); // Добавляем в конец <body>


Если нужно добавлять элементы в разные места:

appendChild() — добавляет в конец родителя.

prepend() — добавляет в начало.

before() и after() — добавляют перед или после элемента.

title.after(newDiv); // Вставит newDiv сразу после title

// С помощью append() можно сразу добавлять текст и несколько элементов
const container = document.querySelector(".container");
container.append("Просто текст", document.createElement("span"));


6. Удаление элементов

Самый актуальный способ — remove().

newDiv.remove(); // Удалит элемент из DOM


Раньше приходилось делать так (и это было неудобно):

newDiv.parentNode.removeChild(newDiv); // Старый подход


7. Обработчики событий (современный подход)

Раньше часто использовали`onclick`, но перезаписывает предыдущие обработчики и плохо управляется. Лучше используйте addEventListener.

const button = document.querySelector("#myButton");

button.addEventListener("click", () => {
alert("Кнопка нажата!");
});


Мы рассказали только часть советов. Если знаете что-то ещё важное, о чем мы не рассказали тут, поделитесь в комментариях.

#простымисловами #фронтенд
🤓21
Что такое рекурсия

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

Как работает рекурсия?

У рекурсии всегда есть две важные части:

1. Базовый случай — когда задача становится настолько простой, что её можно решить сразу, без новых вызовов.

2. Рекурсивный случай — когда функция вызывает саму себя, но с более простыми данными.

Максимально простой пример рекурсии на Python

Давайте посчитаем факториал 3 (пишется как 3!) — это 3 * 2 * 1 = 6.

Вот код:

def factorial(n):
if n == 0: # Базовый случай: если n равно 0, возвращаем 1
return 1
else: # Рекурсивный случай: n умножаем на факториал числа поменьше
return n * factorial(n-1)


Как это работает шаг за шагом для `factorial(3)`:

1. factorial(3): 3 * factorial(2)

2. factorial(2): 2 * factorial(1)

3. factorial(1): 1 * factorial(0)

4. factorial(0): возвращает 1 (базовый случай)

5. Теперь идём обратно:

- 1 * 1 = 1

- 2 * 1 = 2

- 3 * 2 = 6

Итог: factorial(3) = 6.

#простымисловами #рекурсия
👍4
Простыми словами: Как хранятся пароли в базах данных

Пароли в базе данных не хранятся в виде обычного текста, который можно просто прочитать (если код писал адекватный человек). Вместо этого их превращают в специальные зашифрованные коды с помощью процесса, который называется хеширование. Эти коды называются хешами, и они выглядят как случайный набор символов. Главное — из хеша нельзя узнать исходный пароль, но можно проверить, правильный ли пароль ввёл пользователь.

Как это работает?

Когда вы придумываете пароль при регистрации, система его хеширует (превращает в код) и сохраняет этот код в базе данных.

Когда вы входите в систему и вводите пароль, система снова его хеширует и сравнивает с тем кодом, что уже есть в базе. Если они совпадают — вход разрешён.

Почему так делают?

— Безопасность. Если кто-то взломает базу данных, он увидит только хеши, а не настоящие пароли. Без исходного пароля хеши бесполезны для входа.
— Секретность. Даже люди, которые управляют системой, не могут узнать твой пароль.

По сути, пароли в базе — это не сами пароли, а их «закодированные отпечатки». Это как замок, который открывается только правильным ключом, но сам ключ нигде не записан. Даже если базу украдут, твои данные останутся защищёнными.

На картинке выше пример схемы хеширования паролей для хранения в БД.

#простымисловами #безопасность #бд
👍82
Что такое очередь и где её применяют

Очередь (queue) — ряд данных, хранящий элементы последовательным образом. Очередь похожа на стек, но в отличие от него, работает по принципу FIFO — First In, First Out (англ. «первым пришёл — первым ушёл»). Данные добавляют в конец, а извлекают из начала.

Для понимания, приведем пример: очередь людей. Последний занял место — последним и будешь, а первый — первым ее и покинет.

Бывают неклассические, двусторонние очереди. В них можно добавлять элементы и извлекать их из начала и конца структуры. Элементы посередине недоступны.

Применение очередей:
— реализация очередей, например на доступ к определённому ресурсу;
— управление потоками в многопоточных средах;
— генерация значений.
— для создания буферов.

#простымисловами
👍3
Что такое утиная типизация

Простыми словами, утиная типизация — это когда в программировании нас интересует не то, как называется объект или к какому классу он относится, а то, что он умеет делать. Если объект ведет себя как утка — например, умеет крякать и плавать, — то для программы он и есть утка, даже если это совсем другой объект. Ведь, если оно выглядит как утка, плавает как утка и крякает как утка, то это, наверное, утка.

В Python типы объектов проверяются не заранее (как в некоторых других языках), а прямо во время работы программы за счет динамической типизации. Утиная типизация в Python означает, что вы можете использовать любой объект в коде, если у него есть нужные вам методы или свойства. Python не заставляет вас говорить: «Это должна быть утка». Ему достаточно, что объект умеет делать то, что вы от него хотите.

Представьте, что у вас есть функция:

def заставить_крякать(объект):
объект.крякать()


Эта функция ожидает, что у объекта будет метод крякать(). Теперь создадим два класса:

class Утка:
def крякать(self):
print("Кря-кря!")

class Человек:
def крякать(self):
print("Эээ... Кря-кря?")


И используем их:

утка = Утка()
человек = Человек()

заставить_крякать(утка) # Вывод: Кря-кря!
заставить_крякать(человек) # Вывод: Эээ... Кря-кря?


Функция заставить_крякать работает и с Утка, и с Человек, потому что у обоих есть метод крякать(). Python не проверяет, утка это или человек, — ему важно только, что метод есть.

Такой подход дает нам гибкость и простоту при работе с кодом. С другой стороны поддерживать его становится сложнее, а следовательно, возрастает риск появления ошибок.

#простымисловами #python
👍4
Гайд: что такое хеш-таблицы

Представьте, что вам нужно мгновенно находить нужные данные среди миллионов записей — например, определять, есть ли пользователь в базе, или быстро подсчитывать количество посещений страницы. Обычный массив или список справится с этим за O(n), а хэш-таблица — за O(1) в среднем.


Внутри гайд подробно и с примерами рассказываем:

• Что такое хеш-функция
• Как работают хэш-таблицы
• Основные операции с хеш-функциями

Сохраняйте, это точно пригодится

#hash #простымисловами
👍9
As Code: очередной тренд или будущее разработки ПО?

Обычная практика в IT-командах: все решения, договоренности живут ОТДЕЛЬНО от кода — в чатах, документах, головах. Со временем происходит масштабирование и всё это превращается в такой хаос, что проще снести и написать с нуля.

Тут на помощь приходит As Code.

Это не просто методология, а философия, где все — от инфраструктуры до документации и политик безопасности — становится кодом.


Рассказываем почему As Code критически важен для современных IT-компаний и как он эволюционировал c 1970-х годов: https://tprg.ru/7gx5

#простымисловами #архитектура
👍8😁1
Чем отличаются реляционные БД от нереляционных

Реляционные и нереляционные базы данных — это два разных способа хранения и организации информации. Давайте разберём их отличия простыми словами.

Реляционные базы данных похожи на шкаф с ящиками, где всё упорядочено. Каждый ящик — это как таблица (представьте Excel), в которой:

— Есть чёткие столбцы, например, «Имя», «Фамилия», «Телефон».
— Каждая строка — это данные об одном объекте, например, о клиенте.
— Таблицы связаны между собой. Например, можно соединить таблицу «Клиенты» с таблицей «Заказы», чтобы узнать, кто что заказал.

В реляционных БД, например, MySQL или PostgreSQL, всё организовано и легко искать информацию даже с помощью сложных запросов вроде «покажи клиентов, купивших товар X». Но если данные часто меняются или их структура нечёткая, нужно «перестраивать шкаф», а при больших объёмах такие БД могут тормозить

Нереляционные базы, например, MongoDB или Redis — это как большая коробка, куда можно кидать вещи без строгого порядка. Здесь данные хранятся не в таблицах, а в разных форматах:

— Документы (как файлы с информацией).
— Ключ-значение (как словарь).
— Графы (для связей, например, в соцсетях).
— Колонки (для больших данных).

Такой подход даёт нам гибкость для хранения любых данных, даже если они часто меняются. А также позволяют быстро работать с большими объёмами и легко масштабируются. Взамен на эти преимущества они усложняют нам создание сложных запросов, а также поиск чего-то конкретного.

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

#простымисловами #бд
👍9
Что такое FastAPI

FastAPI — это современный фреймворк для создания веб-API на Python. Он предназначен для быстрого и эффективного создания сервисов, которые обрабатывают запросы пользователей и возвращают ответы. Например, с помощью FastAPI можно создать API для отображения прогноза погоды, управления списком задач или даже сложной системы обработки данных.

FastAPI заслужил свою популярность благодаря нескольким ключевым преимуществам:

— Он построен на современных технологиях, что делает его одним из самых быстрых фреймворков для Python. Это особенно важно для проектов, где скорость ответа критична.
— Для создания базового API достаточно написать всего несколько строк кода. Это снижает порог входа для новичков и ускоряет разработку.
— FastAPI автоматически генерирует интерактивную документацию (например, в формате Swagger), которая позволяет другим разработчикам легко понять, как работает ваш API, и протестировать его прямо в браузере.

FastAPI предлагает множество возможностей, которые делают его универсальным инструментом для самых разных задач: интеграцию БД, автоматическую проверку входных данных, масштабируемость.

Чтобы показать, насколько просто начать работать с FastAPI, вот пример минимального кода:

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
return {"message": "Привет, мир!"}


Если запустить этот код и открыть в браузере адрес https://localhost:8000, вы увидите JSON-ответ: {"message": "Привет, мир!"}. А если перейти по адресу https://localhost:8000/docs, вы получите доступ к автоматически сгенерированной документации.

#простымисловами #fastapi #python
👍3
Forwarded from Веб-страница
Что такое прототипные методы в JavaScript

Давайте сегодня разберем одну из ключевых концепций в JavaScript — прототипные методы. Что это такое и какую роль они играют в нашем коде?

В JavaScript каждое значение имеет прототип — объект, от которого оно «унаследует» свойства и методы. Это позволяет создавать структуры, которые могут делиться функциональностью. Прототипы помогают избежать дублирования кода и облегчить его поддержку.

Как работают прототипные методы?

Когда мы создаем объект, он может использовать методы, определенные в его прототипе. Например, у всех объектов, созданных на основе Array, есть общие методы, такие как .push() и .pop(). Эти методы определены в Array.prototype. Если вы не знаете, что такое prototype, подумайте о нем как о шаблоне для создания объектов.

Давайте рассмотрим простой пример. Мы создадим конструктор для объекта Person и добавим метод greet в его прототип:

function Person(name) {
this.name = name;
}
// Добавляем метод greet в прототип Person
Person.prototype.greet = function() {
console.log(`Привет, меня зовут ${this.name}!`);
};
// Создаем нового человека
const alice = new Person('Алиса');
const bob = new Person('Боб');
// Вызываем метод greet
alice.greet(); // Привет, меня зовут Алиса!
bob.greet(); // Привет, меня зовут Боб!


В этом примере метод greet не дублируется для каждого отдельного объекта, а хранится в прототипе. Это экономит память и делает код более организованным.

Использование прототипов полезно по нескольким причинам:

1. Экономия памяти. Методы хранятся в одном месте, а не копируются в каждый объект.
2. Упрощение кода. Легче добавлять, изменять и удалять методы.
3. Наследование. Можно создавать иерархии объектов, где один объект наследует свойства и методы другого.

Если у вас есть вопросы или хотите обсудить тему подробнее, пишите в комментариях!

#простымисловами
❤‍🔥4
5 правил для код ревью

1. Есть вопрос — спрашивай. Цель код ревью — делать все изменения в кодовой базе проекта понятными каждому разработчику. Без вопросов в сомнительных местах добиться этого будет невозможно.

2. Цель изменений в коде должна быть понятна. Если вы отправляете свой код на ревью — о донесении этих смыслов должны позаботиться вы. Если вы проверяете чужой код, то должны убедиться, что понимаете, какую задачу он решает.

3. Изменения в коде должны быть минимальными. На каждый код ревью не должно приходиться больше 10–100 строк кода. В большинстве случае изменения на 1000 строк можно разбить на десятки понятных частей. Это же правило стимулирует регулярный (ежедневный) код ревью.

4. Наличие стандартов. В каждой команде должны быть чётко прописанные стандарты кода, чтобы каждый раз вам не приходилось спорить из-за банального написания переменных (типа camelCase или underscore_case).

5. Баланс. Вы не живём в идеальном мире и всегда будут те, кто получает удовольствие от код ревью, и те, кто ненавидит его. Учитывайте это и старайтесь быть уважительным и при создании новых изменений, и при просмотре чужих.

Источник: dev.to

#простымисловами #команда
4👍2🤓2
В чем разница между классами StringBuffer и StringBuilder в языке Java?

Когда вы выбираете между StringBuffer и StringBuilder, главное отличие — это работа с потоками и производительность.

StringBuffer — это класс, который можно безопасно использовать в многопоточной среде. То есть, если в вашей программе несколько потоков (например, параллельные задачи), и они одновременно работают со строками, StringBuffer позаботится о том, чтобы данные не перепутались. Он использует синхронизацию, что делает его безопасным, но немного более медленным.

StringBuilder — работает быстрее, но не использует синхронизацию. Поэтому он не подходит для многопоточной среды. Зато в обычных программах, где всё выполняется в одном потоке, StringBuilder будет работать эффективнее и быстрее.

Если говорить проще:

— Используйте StringBuilder, если вы пишете обычный код без многопоточности. Это быстрее и проще.

— Используйте StringBuffer, если ваша программа запускает несколько потоков, и вы хотите избежать ошибок при одновременном доступе к строкам.

#простымисловами #java
Что такое MCP и зачем он нужен?

MCP (Model Context Protocol) — это способ передать языковой модели информацию о вас и вашей задаче: кто вы, чем занимаетесь, какой у вас уровень и как вы предпочитаете получать ответы.

MCP позволяет:
— не повторять одно и то же при каждой сессии;
— получать более точные и полезные ответы;
— работать с внешними сервисами (календарь, почта, GitHub) с учётом ваших целей.

🔍 Где используется MCP прямо сейчас?

— ChatGPT с памятью: помнит, что вы учите Python, и не перегружает вас сложностями.
— GitHub Copilot Chat: знает, какой у вас файл, стек и задачи, и подсказывает по делу.
— Интеграции с Google Calendar или Gmail: модель понимает, что у вас есть календарь и может по команде создать событие.
— Notion, Canva, Figma AI: понимают стиль и контекст текущего проекта.

MCP ≠ просто память

Это структурированный контекст, который помогает модели работать как персональный помощник, а не просто чат с нуля.

Именно MCP делает общение с ИИ полезным, осознанным и человечным.

#простымисловами
👍5
Что такое merge и rebase в Git — и в чём между ними разница?

Когда несколько человек (или вы сами) работают над одним проектом, у вас появляются разные ветки с изменениями. Чтобы соединить их — используют merge или rebase. Оба делают одно и то же: включают изменения из одной ветки в другую, но делают это по-разному.

git merge — «просто объединить»

Представьте: у вас есть ветка main, а вы работаете в ветке feature. Когда фича готова, вы хотите добавить её в main.

Если сделать:
git checkout main
git merge feature


Git просто добавит новый коммит, который объединит все изменения из feature. История при этом сохранится как была — видно, где шли параллельные ветки. Это безопасно и удобно для командной работы.

Преимущества:

— история честная, всё видно;
— легко откатить.

🚫 Минус: история становится «ветвистой» — особенно при частых слияниях.

git rebase — «переписать, как будто всё было по порядку»

rebase берёт все ваши коммиты из ветки feature и как бы переносит их в конец ветки main, меняя их «время» и «место» в истории:
git checkout feature
git rebase main


Теперь ветка feature выглядит так, будто вы сначала получили все обновления из main, а потом начали работать. История становится прямой и аккуратной, без лишних ответвлений.

Преимущества:

— история читается как по линейке;
— удобно перед публикацией.

🚫 Минусы:

— может быть опасно, если кто-то уже использует вашу ветку (можно поломать историю при push).

Когда использовать что?

merge — когда работаете в команде. Безопаснее, история прозрачная.

rebase — когда хотите навести порядок в истории до слияния (например, перед git merge), или если вы единственный, кто работает с веткой.

#простымисловами #git
3🔥2
Что такое прототипное наследование в JavaScript?

Предлагаем вам новый формат — мы #простымисловами рассказываем о программировании, но прежде чем прочитать, попробуйте самостоятельно вспомнить о чем речь, чтобы проверить свои знания. Пишите своё понимание в комментарии, а только потом читайте наше объяснение.

В других языках (например, Java или C#) есть классы — «шаблоны», по которым создаются объекты, и у которых можно наследовать методы и свойства.

В JavaScript всё устроено немного иначе — он изначально не был «классовым», и вместо этого использует **прототипы**.

В JavaScript **каждый объект внутри себя хранит ссылку на другой объект — прототип**.

Если вы обращаетесь к свойству или методу, которого нет в текущем объекте, JavaScript заглянет в его прототип. Не нашёл там? Пойдёт дальше — в прототип прототипа.

Эта цепочка называется **прототипной цепочкой**.
const animal = {
eats: true
};

const rabbit = {
jumps: true
};

rabbit.__proto__ = animal;

console.log(rabbit.jumps); // true (есть в самом объекте)
console.log(rabbit.eats); // true (нашёлся в прототипе)


Здесь rabbit не хранит eats напрямую, но когда вы к нему обращаетесь — движок пойдёт по цепочке в animal и найдёт.

**Почему это удобно?**

1. Можно «раздавать» общие методы всем объектам через прототип — не дублируя код.
2. Можно строить целые цепочки наследования без классов.
3. Всё это гибко и динамично.

Сейчас в JavaScript уже появились **классы**, но внутри они всё равно реализованы через прототипы — просто это более привычный синтаксис для тех, кто приходит из других языков.

Так что прототипное наследование — это способ объектов «подглядывать» в другие объекты за свойствами и методами. И именно так устроен весь JavaScript под капотом.

#javascript
🤓2