برنامه نویسی ماژولار و غیر ماژولار در زبان JavaScript
بِرَه، بریم سرِ یه گپِ جانانه دربارهی «ماژولار vs غیرماژولار» توی JavaScript؛ مثلِ اینه که داریم مقایسه میکنیم بین یه فروشگاهِ زنجیرهایِ بزرگ که هر قسمتش یه دپارتمانِ مشخصِ (لباس، لوازمِ آرایشی، خواروبار)، با یه انباری که همهی جنسا رو تویِ یه کُپه ریختی و مشتری باید خودش هُرِ بزنه تا شامپو پیدا کنه! بذار مثلِ همونی باشم که داره واسه دوستِ تازهکارِ JS توضیح میده، خطِ اولِ کد تا آخر.
۱) غیرماژولار (Monolithic) در JS
ویژگیها:
– یه فایلِ ۲۰۰۰ خطیِ app.js؛
– همهچی تویِ Global ریخته (window.utils, window.user, window.cart …)؛
– تابعها و متغیرها همدیگه رو مستقیم صدا میزنن؛
– کپیپیستِ بیرویه؛
– اگر بخوای یه بخش رو تست کنی، باید کلِ فایل بیاد بالا.
نمونهِ ساده (ولی دردناک):
index.html
<script src="app.js"></script>
app.js
// همهچی تویِ یه فایلِ ۶۰۰ خطی
const users = [];
let totalPrice = 0;
function addUser(name) {
users.push({ name });
}
function calcTax(price) {
return price * 0.09;
}
function addToCart(price) {
totalPrice += price;
const tax = calcTax(totalPrice);
console.log(`Total+Tax=${totalPrice + tax}`);
}
// DOM
document.getElementById("add").onclick = () => {
const name = prompt("Name?");
addUser(name);
addToCart(100);
};
حالا بخوای:
– تابعِ calcTax رو تستِ واحد بزنی؟ باید کلِ فایل رو لود کنی.
– یه جایِ دیگه بخوای از calcTax استفاده کنی؟ کپیپیست.
– دو تا برنامهنویسِ همزمان؟ merge hell.
۲) ماژولار (Modular) در JS
راهِ امروزی: از ES Module (ESM) یا CommonJS (Node) استفاده کن؛ هر فایل یه «ماژول»ِ، فقط اونچیزی رو export میکنه که لازمِ.
همون پروژه، حالا شکستهشده:
utils/tax.js
export const TAX_RATE = 0.09;
export function calcTax(amount) {
return amount * TAX_RATE;
}
entities/user.js
export function createUser(name) {
return { name, id: Math.random() };
}
services/cart.js
import { calcTax } from '../utils/tax.js';
let total = 0;
export function addToCart(price) {
total += price;
return total + calcTax(total);
}
export function resetCart() { total = 0; }
ui/app.js
import { createUser } from '../entities/user.js';
import { addToCart, resetCart } from '../services/cart.js';
document.getElementById("add").onclick = () => {
const name = prompt("Name?");
const user = createUser(name);
const final = addToCart(100);
console.log(`User ${user.name} pays ${final}`);
};
index.html
<script type="module" src="ui/app.js"></script>
حالا:
– میتونی tax.test.js بسازی، فقط همون ماژول رو ایمپورت کنی و تست بزنی (Jest، Vitest).
– اگر بخوای TAX_RATE عوض کنی، فقط یه جاست.
– کسی نمیتونه تصادفاً total رو دستکاری کنه (private داخلِ ماژول).
– Webpack / Vite / Rollup میتونه بیاد «درخت تکاندار» (tree-shake) کنه؛ فقط همون بخشی که استفاده شده تویِ bundle میره.
۳) مقایسهِ سریع
| غیرماژولار | ماژولار (ESM) | |
|---|---|---|
| متغیرِ Global | داره، تداخلِ نام | نداره، scope ماژولی |
| تستِ واحد | سخت | import و done |
| بارگذاریِ مرورگر | یه فایلِ بزرگ | ماژولِ کوچیک + lazy-load |
| Bundle Size | کلِ فایل | فقط ماژولهای استفادهشده |
| همکاریِ تیمی | merge سخت | هرکس رویِ یه ماژول کار میکنه |
| درکِ کد | باید ۲۰۰۰ خط بخونی | فقط همون دپارتمان رو میخونی |
۴) در Node.js هم همینه
غیرماژولار:
// server.js
const express = require('express');
const app = express();
let users = [];
app.get('/users', (req,res)=> res.json(users));
app.listen(3000);
ماژولار:
// users/repo.js
let users = [];
exports.findAll = () => users;
exports.add = u => users.push(u);
// users/controller.js
const repo = require('./repo');
exports.list = (req, res) => res.json(repo.findAll());
// routes.js
const ctrl = require('./users/controller');
app.get('/users', ctrl.list);
حالا اگر بخوای دیتا رو از Mongo بخونی، فقط repo.js رو عوض میکنی؛ کنترلر و روت بیخبر میمونن.
۵) چه جوری بیشازحد ماژولار نشیم؟
– برایِ ۵۰۰ خط کد، ۴۰ تا فایل نساز!
– تا وقتی یه «مسئلهی مستقل» نداری، نُو (new) ماژول نکن.
– از «بارrel exports» استفاده کن:
// utils/index.js
export { calcTax } from './tax.js';
export { formatMoney } from './money.js';
حالا بیرون فقط:
import { calcTax, formatMoney } from '../utils';
۶) چکلیستِ ۳۰ثانیهای
۱) فایلِ JSام رو باز کردی، اگر بالاش ۱۰ تا متغیرِ Global دیدی = قرمزِ.
۲) اگر تویِ هر تابع، DOM + محاسبه + شبکه همهچی تویِ همِ = قرمزِ.
۳) اگر بتونی یه *.test.js بسازی و فقط با یه import تست بزنی = سبزِ.
۷) یادت باشه: «ماژولار» فقط «چندتا فایل» نیست
– Single Responsibility: هر ماژول فقط یه «علتِ تغییر» داشته باشه.
– Loose Coupling: ماژولِ «کاربر» نباید مستقیم بره داخلِ localStorage بنویسه؛ یه «storage service» صدا بزنه.
– Dependency Injection: اگر فردا خواستی calcTax رو باِ calcTax2025 عوض کنی، فقط همون جا تزریقش کن، نه اینکه ۱۰۰ تا فایل رو دستکاری کنی.
خلاصهِ یکخطی
کدنویسیِ غیرماژولار = میریزی همهچی تویِ یه قابلمه؛ برنامهنویسیِ ماژولار = میچینی تویِ قفسههایِ شفاف، هرکس فقط همون ادویهای رو برمیداره که لازم داره، بدونِ اینکه نمکِ مرغُ بریزه تویِ کیکِ شکلاتی!
پست های مرتبط
27 آبان 1404
27 آبان 1404
27 آبان 1404
27 آبان 1404
27 آبان 1404