جامعه جاوا اسکریپت راه های مختلفی برای سازماندهی کدها در ماژول ها پیدا کرد. دریابید که چگونه سیستم ماژول در اکوسیستم جاوا اسکریپت تکامل یافته است.
مفهوم ماژول ها از پارادایم برنامه نویسی مدولار می آید. این پارادایم پیشنهاد میکند که نرمافزار باید از اجزای جداگانه و قابل تعویض به نام «ماژولها» با تجزیه توابع برنامه به فایلهای مستقلی تشکیل شود که میتوانند به صورت جداگانه یا همراه در یک برنامه کاربردی کار کنند.
یک ماژول یک فایل مستقل است که کد را برای پیادهسازی عملکردهای خاص و ارتقای قابلیت استفاده مجدد و سازماندهی کپسوله میکند.
در اینجا سیستمهای ماژول مورد استفاده در برنامههای جاوا اسکریپت، از جمله الگوی ماژول، سیستم ماژول CommonJS مورد استفاده در اکثر برنامههای Node.js و سیستم ES6 Module را پوشش میدهید.
الگوی ماژول
قبل از معرفی ماژول های بومی جاوا اسکریپت، الگوی طراحی ماژول به عنوان یک سیستم ماژول برای محدوده متغیرها و توابع به یک فایل واحد استفاده می شد.
این با استفاده از عبارات تابع بلافاصله فراخوانی شده، که عموماً به عنوان IIFE شناخته می شوند، پیاده سازی شد. IIFE یک تابع غیرقابل استفاده مجدد است که به محض ایجاد اجرا می شود.
در اینجا ساختار اصلی یک IIFE آمده است:
(function () {
//code here
})();
(() => {
//code here
})();
(async () => {
//code here
})();
بلوک کد بالا IIFE های مورد استفاده در سه زمینه مختلف را توصیف می کند.
IIFEها به این دلیل استفاده میشوند که متغیرهای اعلامشده در داخل یک تابع در محدوده تابع قرار میگیرند، و آنها را فقط در داخل تابع قابل دسترسی میسازد، و به این دلیل که توابع به شما اجازه میدهند دادهها را برگردانید (آنها را در دسترس عموم قرار میدهد).
مثلا:
const foo = (function () {
const sayName = (name) => {
console.log(`Hey, my name is ${name}`);
};
//Exposing the variables
return {
callSayName: (name) => sayName(name),
};
})();
//Accessing exposed methods
foo.callSayName("Bar");
بلوک کد بالا نمونه ای از نحوه ایجاد ماژول ها قبل از معرفی ماژول های بومی جاوا اسکریپت است.
بلوک کد بالا حاوی یک IIFE است. IIFE حاوی تابعی است که با بازگرداندن آن قابل دسترسی است. تمام متغیرهای اعلام شده در IIFE از دامنه جهانی محافظت می شوند. بنابراین، روش (sayName) تنها از طریق تابع عمومی، callSayName قابل دسترسی است.
توجه داشته باشید که IIFE در یک متغیر ذخیره شده است، foo. این به این دلیل است که بدون اشاره متغیری به مکان آن در حافظه، متغیرها پس از اجرای اسکریپت غیر قابل دسترسی خواهند بود. این الگو به دلیل بسته شدن جاوا اسکریپت امکان پذیر است.
سیستم ماژول CommonJS
سیستم ماژول CommonJS یک قالب ماژول است که توسط گروه CommonJS برای حل مسائل حوزه جاوا اسکریپت با اجرای هر ماژول در فضای نام آن تعریف شده است.
سیستم ماژول CommonJS با وادار کردن ماژولها به صادرات متغیرهایی که میخواهند در معرض ماژولهای دیگر باشند، کار میکند.
این سیستم ماژول برای جاوا اسکریپت سمت سرور (Node.js) ایجاد شده است و به این ترتیب، به طور پیش فرض در مرورگرها پشتیبانی نمی شود.
برای پیاده سازی ماژول های CommonJS در پروژه خود، ابتدا باید NPM را در برنامه خود با اجرای:
npm init -y
متغیرهایی که به دنبال سیستم ماژول CommonJS صادر می شوند را می توان به این صورت وارد کرد:
//randomModule.js
//installed package
const installedImport = require("package-name");
//local module
const localImport = require("/path-to-module");
ماژول ها در CommonJS با استفاده از دستور require وارد می شوند، که یک فایل جاوا اسکریپت را می خواند، فایل خوانده شده را اجرا می کند و شی صادرات را برمی گرداند. شی صادرات شامل تمام صادرات موجود در ماژول است.
شما می توانید یک متغیر را به دنبال سیستم ماژول CommonJS با استفاده از صادرات نامگذاری شده یا صادرات پیش فرض صادر کنید.
صادرات به نام
صادرات نامگذاری شده صادراتی است که با نام هایی که به آنها اختصاص داده شده است مشخص می شود. صادرات نامگذاری شده، برخلاف صادرات پیشفرض، امکان صادرات چندگانه در هر ماژول را فراهم میکند.
مثلا:
//main.js
exports.myExport = function () {
console.log("This is an example of a named export");
};
exports.anotherExport = function () {
console.log("This is another example of a named export");
};
در بلوک کد بالا، دو تابع با نام (myExport و AnotherExport) را با پیوست کردن آنها به شی exports صادر می کنید.
به طور مشابه، می توانید توابعی مانند زیر را صادر کنید:
const myExport = function () {
console.log("This is an example of a named export");
};
const anotherExport = function () {
console.log("This is another example of a named export");
};
module.exports = {
myExport,
anotherExport,
};
در بلوک کد بالا، شی exports را روی توابع نامگذاری شده تنظیم می کنید. شما فقط می توانید شی صادرات را از طریق شی ماژول به یک شی جدید اختصاص دهید.
اگر بخواهید این کار را به این طریق انجام دهید، کد شما با خطا مواجه می شود:
//wrong way
exports = {
myExport,
anotherExport,
};
دو راه برای وارد کردن صادرات با نام وجود دارد:
1. تمام صادرات را به عنوان یک شی واحد وارد کنید و با استفاده از علامت نقطه به آنها به طور جداگانه دسترسی داشته باشید.
مثلا:
//otherModule.js
const foo = require("./main");
foo.myExport();
foo.anotherExport();
2. ساختار صادراتی را از شیء صادراتی جدا کنید.
مثلا:
//otherModule.js
const { myExport, anotherExport } = require("./main");
myExport();
anotherExport();
یک چیز در همه روش های واردات رایج است، آنها باید با همان نام هایی وارد شوند که با آنها صادر شده اند.
صادرات پیش فرض
صادرات پیشفرض صادراتی است که با هر نام دلخواه شما مشخص میشود. شما فقط می توانید یک صادرات پیش فرض در هر ماژول داشته باشید.
مثلا:
//main.js
class Foo {
bar() {
console.log("This is an example of a default export");
}
}
module.exports = Foo;
در بلوک کد بالا، یک کلاس (Foo) را با تخصیص مجدد شی exports به آن صادر می کنید.
وارد کردن صادرات پیشفرض مشابه واردات صادرات با نام است، با این تفاوت که میتوانید از هر نامی که انتخاب میکنید برای وارد کردن آنها استفاده کنید.
مثلا:
//otherModule.js
const Bar = require("./main");
const object = new Bar();
object.bar();
در بلوک کد بالا، صادرات پیشفرض Bar نام داشت، اگرچه میتوانید از هر نام دلخواه خود استفاده کنید.
سیستم ماژول ES6
سیستم ماژول هارمونی ECMAScript، که به عنوان ماژول های ES6 شناخته می شود، سیستم رسمی ماژول جاوا اسکریپت است.
ماژولهای ES6 توسط مرورگرها و سرورها پشتیبانی میشوند، اگرچه قبل از استفاده از آنها به پیکربندی کمی نیاز دارید.
در مرورگرها، باید نوع را به عنوان ماژول در تگ واردات اسکریپت مشخص کنید.
اینطوری:
//index.html
<script src="./app.js" type="module"></script>
در Node.js باید در فایل package.json نوع را روی ماژول تنظیم کنید.
اینطوری:
//package.json
"type":"module"
همچنین می توانید متغیرها را با استفاده از سیستم ماژول ES6 با استفاده از صادرات نامگذاری شده یا صادرات پیش فرض صادر کنید.
صادرات به نام
مشابه واردات نامگذاریشده در ماژولهای CommonJS، آنها با نامهایی که به آنها اختصاص داده شده است شناسایی میشوند و اجازه صادرات چندگانه در هر ماژول را میدهند.
مثلا:
//main.js
export const myExport = function () {
console.log("This is an example of a named export");
};
export const anotherExport = function () {
console.log("This is another example of a named export");
};
در سیستم ماژول ES6، صادرات نامگذاری شده با پیشوند متغیر با کلمه کلیدی صادرات صادر می شود.
صادرات نامگذاری شده را میتوان به روشهای مشابه CommonJS به ماژول دیگری در ES6 وارد کرد:
- ساختارشکنی صادرات مورد نیاز از هدف صادرات.
- وارد کردن تمام صادرات به عنوان یک شی واحد و دسترسی به آنها به طور جداگانه با استفاده از نماد نقطه.
در اینجا مثالی از ساختارزدایی آورده شده است:
//otherModule.js
import { myExport, anotherExport } from "./main.js";
myExport()
anotherExport()
در اینجا یک مثال از وارد کردن کل شی است:
import * as foo from './main.js'
foo.myExport()
foo.anotherExport()
در بلوک کد بالا، ستاره (*) به معنای “همه” است. کلمه کلیدی as شی exports را به رشته ای که به دنبال آن است، در این مورد foo اختصاص می دهد.
صادرات پیش فرض
مشابه صادرات پیشفرض در CommonJS، آنها با هر نامی که شما انتخاب میکنید شناسایی میشوند و شما فقط میتوانید یک صادرات پیشفرض در هر ماژول داشته باشید.
مثلا:
//main.js
class Foo {
bar() {
console.log("This is an example of a default export");
}
}
export default Foo;
صادرات پیشفرض با افزودن کلمه کلیدی پیشفرض پس از کلمه کلیدی صادرات و به دنبال آن نام صادرات ایجاد میشود.
وارد کردن صادرات پیشفرض مشابه واردات صادرات با نام است، با این تفاوت که میتوانید از هر نامی که انتخاب میکنید برای وارد کردن آنها استفاده کنید.
مثلا:
//otherModule.js
import Bar from "./main.js";
صادرات مختلط
استاندارد ماژول ES6 به شما این امکان را می دهد که بر خلاف CommonJS هم صادرات پیش فرض و هم صادرات با نام را در یک ماژول داشته باشید.
مثلا:
//main.js
export const myExport = function () {
console.log("This is another example of a named export");
};
class Foo {
bar() {
console.log("This is an example of a default export");
}
}
export default Foo;
اهمیت ماژول ها
تقسیم کد به ماژولها نه تنها خواندن آنها را آسانتر میکند، بلکه آن را قابل استفادهتر و قابل نگهداریتر میکند. ماژول ها در جاوا اسکریپت همچنین کد شما را کمتر در معرض خطا قرار می دهند، زیرا همه ماژول ها به طور پیش فرض در حالت سخت اجرا می شوند.