بررسی ماژول‌ها (Modules) در جاوااسکریپت

با ماژول‌ها می‌تونیم یک برنامه بزرگ رو به اجزای کوچیک‌تر تقسیم کنیم تا توسعه راحت بشه و هم خوانایی و نگهداری کد بالا بره. توی این قسمت با کلی نکته درباره ماژول‌ها توی جاوااسکریپت آشنا می‌شیم.

سلام دوستان. ماژول‌ها یکی از مهمترین و پراستفاده‌ترین ویژگی‌ها توی دنیای جاوااسکریپت مدرن هستن و امروزه تقریباً هر برنامه‌ی بزرگ و کوچیکی از این ویژگی بهره می‌بره.

درک ماژول‌ها و نحوه‌ی کاربرد اونها توی جاوااسکریپت اهمیت زیادی داره. چون ابزارهای امروزی مثل فریم‌ورک‌ها خیلی فراوون از این ویژگی استفاده می‌کنن. توی این قسمت با ماژول‌های جاوااسکریپت که توسط ES6 معرفی شدن آشنا می‌شیم و فواید اونها رو بررسی می‌کنیم.

توی این قسمت یاد می‌گیریم که:

  • ماژول چیه؟
  • کلمه‌کلیدی export
  • export default چیه
  • کلمه‌کلیدی import
  • وارد کردن همه چیز
  • وارد کردن عضو export default شده
  • چرا از ماژول‌ها استفاده کنیم
  • استفاده از یک ماژول توی مرورگر
  • تو چه مرورگرهایی می‌تونیم با تگ script با ماژول‌ها کار کنیم


ماژول چیه؟ ?

یک جمله معروف درباره ماژول‌ها یا بطور کلی اصل Separation of concerns (جداسازی وابستگی‌ها) وجود داره:

نویسندگان خوب، کتاب‌ها رو به بخش‌ها و فصل‌های مجزا تقسیم‌بندی می‌کنن. برنامه‌نویس‌های خوب، برنامه‌ رو به بخش‌های مختلف تقسیم‌بندی می‌کنن.

درست مثل یک کتابی که به فصل‌های مجزا تقسیم‌بندی میشه، یک برنامه می‌تونه به قسمت‌های مجزا تقسیم بندی بشه. به هر یک از این قسمت‌ها میگن ماژول (Module).
یک ماژول معمولاُ مستقل از بخش‌های برنامه عمل می‌کنه. توی جاوااسکریپت هر ماژول بصورت یک فایل جداگونه ذخیره میشه و می‌تونه بدون مشکل به یک ماژول دیگه و یا به هسته برنامه اضافه یا برداشته بشه. اعضای یک ماژول (متغیرها، توابع و ... ) فقط توی خود ماژول قابل دسترسی هستن و Global نیستن.

حالا وقت بررسی کردن این ویژگی توی جاوااسکریپت هست.

ما با کلمه‌کلیدی import یک ماژول رو وارد برنامه می‌کنیم و فقط به اعضایی دسترسی داریم که توی ماژول export شده باشن. پس اول Export رو بررسی می‌کنیم.


کلمه‌کلیدی export

با کلمه‌کلیدی export می‌تونیم یک عضو از ماژول مثل یک متغیر رو قابل دسترسی کنیم. برای export کردن متغیرها، توابع، کلاس‌ها و ... از کلمه‌کلیدی export قبل از اون عضو استفاده می‌کنیم. ابتدا یک فایل به اسم دلخواه مثلا artist.js درست می‌کنیم با محتویات زیر:

export const name = &quotMathias"
const favorites = [&quotMusic&quot, &quotPainting&quot];

export function play() {
  return &quot?"
}

export class Draw {
  start() {
    return &quot?"
  }
}

توی ماژول بالا اعضایی که قبل از تعریف اونها از کلمه‌کلیدی export استفاده شده، قابل استفاده در بیرون ماژول هستن. پس به متغیر favorites بیرون از ماژول نمی‌تونیم دسترسی پیدا کنیم.

اگه تعداد اعضای ما زیاد باشن، بجای نوشتن کلمه export قبل از هر عضوی، می‌تونیم آخر ماژول اونها بصورت زیر Export کنیم:

const name = &quotMathias"
const favorites = [&quotMusic&quot, &quotPainting&quot];

function play() {
  return &quot?"
}

class Draw {
  start() {
     return &quot?"
  }
}

export { name, play, Draw };

همچنین میشه یک عضو رو با نام دلخواه Export کرد. برای این کار از کلمه‌کلیدی as هنگام Export کردن استفاده می‌کنیم:

const name = &quotMathias"

function play() {
  return &quot?"
}

export {
    name,
    play as playGuitar,
};


export default چیه؟

ما می‌تونیم مشخص کنیم به صورت پیشفرض، کدوم عضو در نظر گرفته بشه برای export شدن. برای این کار از کلمه‌کلیدی default بعد از export استفاده می‌کنیم:

export default name = &quotMathias"
export const favorites = [&quotMusic&quot, &quotPainting&quot];

یا به این صورت:

const name = &quotMathias"
const favorites = [&quotMusic&quot, &quotPainting&quot];

export {
  name as default,
  favorites
}

بصورت پیشفرض چیزی که ماژول بالا تحویل میده متغیر name هست، مگر اینکه موقع import، عضوی که لازم داریم رو صراحتاً صدا بزنیم. تا الان فقط Export کردیم. حالا باید از چیزایی که Export کردیم استفاده کنیم. برای این کار از کلمه‌کلیدی import استفاده می‌کنیم. توی ادامه با انواع نحوه‌ٔ import کردن آشنا می‌شیم.



کلمه‌کلیدی import

برای استفاده از ماژول artist، یک فایل دیگه می‌سازیم به اسم app.js با محتویات زیر:

import { name, playGuitar, Draw } from './artist';
console.log(name);
console.log(playGuitar());

ما توی خط اول آیتم‌هایی که از ماژول artist احتیاج داریم رو جلوی کلمه import و توی { } نوشتیم. به نحوه آدرس دادن ماژول artist دقت کنید. './artist' یعنی این ماژول توی همین مسیر هست. همچنین اگه پسوند فایل ماژول js هست، لازم نیست پسوند رو بنویسیم.

می‌تونیم اعضای یک ماژول رو با نام دلخواه Import کنیم. برای این کار از کلمه‌کلیدی as هنگام وارد کردن استفاده می‌کنیم:

import { name as artistName, playGuitar, Draw } from './artist';

console.log(artistName);

وارد کردن همه چیز

اگه همه‌ی اعضای یک ماژول رو لازم داریم از * بصورت زیر استفاده می‌کنیم:

import * as myArtist from &quot./artist"

console.log(myArtist.name);

توی این کد همه اعضای ماژول از طریق myArtist که اسم دلخواه ولی اجباری ما هست، مثل خط ۳ قابل دسترسی هستن.


وارد کردن عضو export default شده

توی قسمت export دیدیم که یک ماژول می‌تونه یک عضو رو به عنوان پیشفرض export کنه. حالا برای خوندن این مقدار پیشفرض بصورت زیر import می‌کنیم:

import theArtistName from './artist';

همونطور که می‌بینید دیگه از { } استفاده نشد. به عبارت دیگه، وقتی از { } استفاده نمی‌کنیم، به این معنی هست که می‌خوایم عضو پیشفرض رو import کنیم. همچنین theArtistName یک مقدار دلخواه هست که می‌تونه هر چیزی باشه:

import table from './artist';

console.log(table); // Mathias

اگه در کنار عضو پیشفرض، به اعضای دیگه هم نیاز داشته باشیم به صورت زیر import می‌کنیم:

import myCustomName, { play, Draw } from './artist';




چرا از ماژول استفاده کنیم؟

قابلیت نگهداری

از خوبی‌های استفاده از ماژول اینه که قابلیت نگهداری (Maintainability) برنامه‌ی ما بالاتر میره و بخش‌های مختلف رو میشه راحت‌تر توسعه داد. تصور کنین توسعه و انسجام یک برنامه با یک فایل ۱۰۰ خطی بهتره یا چهار فایل ۲۵ خطی؟ شاید بگیم اینطوری داره تعداد فایل‌ها بیشتر میشه. اما ما قسمت‌های بی‌ربط رو از هم جدا می‌کنیم تا کد ما معنادار بشه.


استفاده مجدد از کدها

یک تکه کد از برنامه که جاهای زیادی داره تکرار میشه رو می‌تونیم جدا و به یک فایل مجزا منتقل کنیم. هر وقت که خواستیم از این ویژگی استفاده کنیم کافیه فقط این فایل رو وارد کنیم.


استفاده از یک ماژول توی مرورگر

با type="module" توی یک تگ script می‌تونیم از یک ماژول توی مرورگر استفاده کنیم. ابتدا یک ماژول بصورت زیر درست می‌کنیم تا از اون توی مرورگر استفاده کنیم:

// add.js
export function add(x, y) {
  return x + y;
}

حالا از ماژول بالا می‌تونیم بصورت زیر توی مرورگر استفاده کنیم:

<!-- ... -->
<body>
  <script type=&quotmodule&quot>
    import { add } from './add.js';

    alert(add(5, 10));
    alert(add(15, 13));
  
</body>

توی کد بالا چیزی که توی script نوشتیم یک ماژول Local هست. باز هم می‌تونیم این ماژول رو ببریم توی یک فایل جدا و روی تگ script با src="..." بهش آدرس بدیم:

// app.js
import { add } from './add.js';

alert(add(1, 4));
alert(add(4, 29));

و توی HTML:

<!-- ... -->
<body>
  <script type=&quotmodule&quot src=&quot./app.js&quot>
</body>

نکته ۱: ماژول‌هایی که توی مرورگر تعریف می‌کنیم هم کپسوله هستن. یعنی به اجزای همدیگه دسترسی ندارن:

<!-- ... -->
<body>
  <script type=&quotmodule&quot>
     var x = 12;
  

  
    alert(x); // x is not defined
  
</body>

نکته ۲: از یک منبع خارجی نمی‌تونیم import کنیم و import ماژول‌ها توی مرورگر باید از همون منبع باشه. یعنی برای مثال اگه روی localhost هستیم، ماژولی که import می‌کنیم باید روی همین localhost باشه. در غیر این صورت مرورگر اجازه دسترسی نمیده. پس کدها بالا رو توی مرورگر از طریق localhost باز کنین.


نکته‌ها

  • حالت سخت‌گیرانه یا Strict Mode توی یک ماژول همیشه فعال هست. پس لازم نیست از "use strict" استفاده کنیم.
  • مقدار this توی ماژول‌ها undefined هست.


Resources:

https://www.sitepoint.com/using-es-modules

https://alligator.io/js/modules-es6

https://javascript.info/modules-intro

https://www.freecodecamp.org/news/javascript-modules-a-beginner-s-guide-783f7d7a5fcc/