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

Ответ

Вместо модулей можно использовать:

  1. Функции - инкапсулируют логику и могут быть переиспользованы
function calculateTotal(price, tax) {
  return price + (price * tax);
}
  1. Классы - группируют связанную логику и состояние
class Calculator {
  add(a, b) { return a + b; }
}
  1. Объекты - простой способ группировки
const utils = {
  formatDate(date) { /* ... */ }
};
  1. IIFE (Immediately Invoked Function Expression) - изолирует область видимости
const counter = (function() {
  let count = 0;
  return { increment() { count++ } };
})();
  1. Миксины/Примеси - через Object.assign или spread оператор
const loggerMixin = {
  log(msg) { console.log(msg); }
};
  1. Замыкания - для инкапсуляции приватных данных

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

Ответ 18+ 🔞

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

Смотри, первое и самое простое — функции. Ну, классика жанра, блядь. Взял кусок логики, завернул в function, и вот тебе уже переиспользуемый кирпичик. Как лопата — тупо, но в хозяйстве всегда пригодится.

function посчитатьИтог(цена, налог) {
  return цена + (цена * налог); // Считаем и не паримся
}

Дальше — классы. Это когда тебе надо не просто логику, а целое состояние с ней связать, как тот самый Герасим с его Муму. Сгруппировал методы, поля, и вперёд.

class Калькулятор {
  прибавить(a, b) { return a + b; } // И всё тут, блядь
}

Если класс — это слишком пафосно, как сюртук на рыбалке, бери объекты. Просто накидал методов в одну кучу, и порядок.

const утилиты = {
  форматироватьДату(дата) { /* ... */ } // Сделал дело — гуляй смело
};

А вот это, сука, интересный трюк — IIFE (Immediately Invoked Function Expression). Выглядит, как какая-то шаманская пляска со скобками, но смысл в чём? Создал функцию и сразу её выебал — выполнил. Всё, что внутри, изолировано, как в банке, а наружу торчит только то, что сам разрешил. Идеально, чтобы не засрать глобальную область видимости.

const счётчик = (function() {
  let счёт = 0; // Приватная переменная, её снаружи не видно, хоть тресни
  return { увеличить() { счёт++ } }; // А наружу торчит только этот метод
})();

Хочешь примешать к объекту функциональность, как шпроты в салат? Пожалуйста — миксины. Берёшь Object.assign или оператор ... (спред, блядь) и натягиваешь на объект новые методы, как презерватив.

const примесьЛоггера = {
  записать(сообщение) { console.log(сообщение); }
};

const мойОбъект = {};
Object.assign(мойОбъект, примесьЛоггера); // И теперь он умеет логировать!

Ну и король инкапсуляции — замыкания. Это когда функция помнит, где родилась, и тащит с собой своё окружение, как бомж свою сумку. Создаёшь переменную внутри функции — и она становится приватной, недоступной снаружи. Красота, ёпта!

function создатьСчётчик() {
  let значение = 0; // Вот она, священная корова, спрятана в замыкании
  return {
    получить() { return значение; },
    увеличить() { значение++; }
  };
}

const мойСчётчик = создатьСчётчик();
мойСчётчик.увеличить();
console.log(мойСчётчик.получить()); // 1
// А вот напрямую к 'значение' не подобраться, хоть головой об стенку бейся!

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