ماژول‌ها (Modules)

Module چیست، ES Modules با export و import، Default و Named Export، Dynamic Import، Module Scope، CommonJS و مدیریت وابستگی‌ها.

Module چیست؟

ماژول فایلی است که کد را کپسوله می‌کند — هر فایل Scope خودش را دارد:

// بدون ماژول — همه در глобال: ❌
// script1.js: var name = "علی";
// script2.js: var name = "سارا";  // تداخل!

// با ماژول — ایزوله: ✓
// هر فایل جدا، import/export برای ارتباط

ES Modules در مرورگر

<!-- type="module" الزامی: -->
<script type="module" src="app.js"></script>

<!-- یا inline: -->
<script type="module">
    import { greet } from "./utils.js";
    console.log(greet("علی"));
</script>
ماژول‌ها: خودکار Strict Mode، فقط یک‌بار اجرا (Singleton)، defer دارند.

Named Export — خروجی نام‌دار

// utils.js — چند خروجی:
export const PI = 3.14159;

export function circleArea(r) {
    return PI * r ** 2;
}

export class Calculator {
    add(a, b) { return a + b; }
}

// یا یک‌جا در انتها:
const multiply = (a, b) => a * b;
const divide = (a, b) => b !== 0 ? a / b : null;
export { multiply, divide };

Named Import

// import با همان نام:
import { PI, circleArea, Calculator } from "./utils.js";

console.log(PI);            // 3.14159
console.log(circleArea(5)); // 78.5...

// تغییر نام — برای تداخل:
import { PI as PI_NUMBER } from "./utils.js";

// همه با یک نام:
import * as Utils from "./utils.js";
console.log(Utils.PI);
console.log(Utils.circleArea(5));

Default Export — خروجی پیش‌فرض

// User.js — فقط یکی default:
export default class User {
    constructor(name) { this.name = name; }
}

// import — هر نامی می‌خواهی:
import User from "./User.js";
import MyUser from "./User.js";  // همان چیز!

// ترکیب default و named:
export default User;
export const VERSION = "1.0";

// import هر دو:
import User, { VERSION } from "./User.js";
Default برای چیز اصلی فایل (کلاس/کامپوننت)، Named برای ابزارها.

Re-Export — صادرکردن مجدد

// index.js — نقطه ورود:
export { default as User } from "./User.js";
export { default as Product } from "./Product.js";
export * from "./utils.js";       // همه ابزارها

// حالا از یک‌جا:
import { User, Product, PI } from "./index.js";

Dynamic Import — بارگذاری پویا

// import() — Promise برمی‌گرداند:
const module = await import("./heavy-chart.js");
module.renderChart(data);

// شرطی:
if (userNeedsCharts) {
    const { Chart } = await import("./chart.js");
    new Chart(element, data);
}

// با then:
import("./analytics.js")
    .then(module => module.trackPageView())
    .catch(err => console.log("لود نشد"));

// Code Splitting — فقط وقتی لازم است لود می‌شود!

Module Scope و Hoisting

// counter.js:
let count = 0;  // خصوصی — خارج از فایل دیده نمی‌شود

export function increment() {
    return ++count;   // دسترسی داخل فایل OK
}

// app.js:
import { increment } from "./counter.js";
increment();
increment();
// count مستقیم قابل دسترسی نیست! ✓

ماژول‌ها Singleton هستند

// config.js:
console.log("اجرا شد — فقط بار اول!");
export const config = { api: "/api" };

// a.js: import { config } from "./config.js";
// b.js: import { config } from "./config.js";
// → "اجرا شد" فقط یک‌بار چاپ می‌شود
// → config در هر دو فایل همان شیء است

import.meta — اطلاعات ماژول

// در ES Module:
console.log(import.meta.url);    // آدرس کامل فایل

// Dynamic import نسبی:
const helpers = await import(new URL("./helpers.js", import.meta.url));

CommonJS — استاندارد Node.js

// utils.js — CJS:
const PI = 3.14159;

function circleArea(r) { return PI * r ** 2; }

// export — module.exports:
module.exports = { PI, circleArea };

// import:
const { PI, circleArea } = require("./utils");

// یا همه:
const utils = require("./utils");
utils.circleArea(5);

ESM در Node.js

// package.json:
// { "type": "module" }

// حالا import کار می‌کند:
import fs from "node:fs";
import path from "node:path";

// یا پسوند .mjs:
// script.mjs — بدون تغییر package.json

مقایسه ESM و CommonJS

ویژگیES ModulesCommonJS
سینتکسimport/exportrequire/module.exports
بارگذاریAsync — می‌شود موازیSync — ترتیبی
Tree Shakingپشتیبانی ✓نه
مرورگربومی ✓نیاز به Bundler
Dynamicimport()require شرطی
مقدارLive Bindingکپی هنگام require

مدیریت وابستگی‌ها با npm

// package.json:
{
    "name": "my-app",
    "type": "module",
    "dependencies": {
        "lodash": "^4.17.21"
    }
}

// نصب:
// npm install lodash

// استفاده:
import _ from "lodash";
_.chunk([1, 2, 3, 4], 2); // [[1,2],[3,4]]

ساختار پروژه ماژولار

src/
    index.js          — نقطه شروع
    utils/
        format.js     — ابزار قالب‌بندی
        validate.js   — اعتبارسنجی
        index.js      — re-export همه
    services/
        api.js        — ارتباط سرور
        auth.js       — احراز هویت
    models/
        User.js
        Product.js

// index.js:
import { formatDate } from "./utils/index.js";
import ApiService from "./services/api.js";

Top-Level await

// در ماژول — بدون wrapper:
const config = await fetch("/config.json").then(r => r.json());

// همه importها بعد از این منتظر می‌مانند:
export const API_URL = config.apiUrl;

// سایر فایل‌ها:
import { API_URL } from "./config.js";  // config لود شده

جمع‌بندی

کارسینتکس
خروجی نام‌دارexport const x
خروجی پیش‌فرضexport default x
ورود نام‌دارimport { x }
ورود همهimport * as ns
پویاimport() — Promise

این مبحث بخشی از دوره آموزش کامل جاوا اسکریپت است.

ابزارهای مرتبط