ساخت اپ های ماژولار جاوا اسکریپت — به زبان ساده
یکی از بزرگترین قابلیتهای ES6، پشتیبانی جاوا اسکریپت از ماژولهای داخلی است. ماژولها به ما امکان میدهند که کد را بین فایلهای مختلف با استفاده از ساختار export و import به اشتراک بگذاریم. این وضعیت بهبود بزرگی نسبت به استفاده از تگهای script و متغیرهای سراسری برای اشتراک کد بین فایلهای مختلف محسوب میشود. در این مقاله در مورد روش استفاده از این قابلیت برای ساخت اپ های ماژولار جاوا اسکریپت صحبت میکنیم.
استفاده از تگهای script مستعد بروز خطا است، چون ترتیب بارگذاری مهم است. ترتیب نادرست اسکریپتها موجب میشود که برنامه، کدی را که هنوز اعلان نشده است، اجرا کند. همچنین مجبور میشویم کد اسپاگتی بدون ساختار واقعی یا ترکیببندی منطق بنویسیم. این مشکل در ماژولها وجود ندارد، زیرا همه چیز مستقیماً بین فایلها اکسپورت و ایمپورت میشود. ضمناً میتوانیم تعریف کد ایمپورتشده را به سادگی بدانیم، زیرا کاملاً مشخص است که کدام ماژولها ایمپورت شده و ارجاع یافتهاند.
اکسپورت و ایمپورت
برای این کد در یک فایل جاوا اسکریپت قابل ایمپورت باشد، باید آنها را صراحتاً با گزاره export اکسپورت کنیم. به این منظور باید عبارت export را در ابتدای متغیر یا ثابتی که میخواهیم برای فایلهای دیگر افشا شود قرار دهیم.
برای نمونه میتوانیم کدی به صورت زیر بنویسیم:
1export let num = 1;
کد فوق متغیر num را اکسپورت میکند، به طوری که ماژولهای دیگر میتوانند آن را import کرده و مورد استفاده قرار دهند. ما میتوانیم هر چیزی را که با var ،let و const اعلان شده و همچنین تابعها و کلاسها را اکسپورت کنیم. آیتمهایی که اکسپورت میشوند، باید در سطح فوقانی اعلان شوند. گزاره export را نمیتوان در جاهای دیگر مانند داخل تابعها و کلاسها استفاده کرد.
میتوان چندین عضو را همزمان اکسپورت کرد. تنها کاری که به این منظور باید انجام داد، این است که همه اعضا را داخل آکولادهایی قرار دهیم که با ویرگول از هم جدا میشوند. برای نمونه میتوانیم کدی مانند زیر بنویسیم:
1const num1 = 1;
2const num2 = 2;
3const num3 = 3;
4export {num1, num2, num3};
کد فوق به ما امکان میدهد که num1 ،num2 و num3 را در فایلهای جاوا اسکریپت دیگر ایمپورت کنیم. اکنون که اعضا را اکسپورت کردهایم، میتوانیم آنها را در فایلهای جاوا اسکریپت دیگر ایمپورت کنیم. بدین منظور میتوان از گزاره import برای ایمپورت یک یا چند عضو در یک ماژول و کار با آنها استفاده کرد. برای نمونه اگر کد زیر را در moduleA.js داشته باشیم:
1const num1 = 1;
2const num2 = 2;
3const num3 = 3;
4export {num1, num2, num3};
در ادامه در moduleB.js میتوانیم کد زیر را برای ایمپورت کردن آیتمها از moduleA.js استفاده کنیم:
1import {num1, num2, num3} from './moduleA'
مسیر پس از کلیدواژه from با یک نقطه آغاز میشود. معنی نقطه آن است که ما در پوشه جاری قرار داریم.
بدین ترتیب در کد فوق فرض شده است که moduleA.js و moduleB.js در پوشه یکسانی قرار دارند. اگر آنها در پوشه متفاوتی باشند، در صورتی که بخواهیم اعضای moduleA.js را در moduleB.js ایمپورت و اکسپورت کنیم، باید مسیر moduleA.js را نسبت به moduleB.js بیان کنیم. برای نمونه اگر moduleA.js یک سطح بالاتر از moduleB.js باشد، در این صورت در moduleB.js میتوانیم کدی مانند زیر بنویسیم:
1import {num1, num2, num3} from '../moduleAFolder/moduleA'
2 نقطه پشت سر هم در جلوی مسیر به آن معنی است که باید یک سطح بالاتر برویم و سپس moduleAFolder و بعد از آن به moduleA.js برسیم.
میتوانیم از ماژولهای جاوا اسکریپت در تگهای script نیز استفاده کنیم. به این منظور باید خصوصیت type تگ script را به صورت module تعیین کنیم تا بتوانیم از آنها استفاده کنیم. برای نمونه اگر بخواهیم از moduleA.js در فایل HTML خود استفاده کنیم، میتوانیم کدی مانند زیر بنویسیم:
1<script type='module' src='moduleA.js'></script>
میتوان از گزارههای import و export در ماژولهای اسکریپت استفاده کرد. آنها در اسکریپتهای معمولی کار نمیکنند.
اسکریپتها به صورت خودکار در حالت strict کار میکنند و از این رو نمیتوانیم به صورت تصادفی متغیرهای سراسری اعلان کرده و کارهای دیگری که بدون فعال شدن حالت strict ممکن هستند را انجام دهیم. همچنین به صورت خودکار به صورت «ناهمگام» (asynchronous) بارگذاری میشوند به طوری که لازم نیست در مورد طولانی بودن اسکریپتها و اخلال در بارگذاری صفحه نگران باشیم. ضمناً گزارههای import و export تنها بین 2 اسکریپت اتفاق میافتند و از این رو نیازی به تعیین متغیرهای سراسری نیست. بدین ترتیب نمیتوان آنها را مستقیماً در کنسول مشاهده کرد.
اکسپورتهای پیشفرض
یک گزینه «اکسپورت پیشفرض» (default export) برای اکسپورت کردن اعضای ماژول وجود دارد.
ما پیشتر متغیر را به روشی اکسپورت کردیم که آن را بر اساس نام ایمپورت کنیم. یک default export نیز وجود دارد که یک عضو منفرد را از یک ماژول بدون نیاز به ارجاع صریح به نام آن در زمان ایمپورت شدن، اکسپورت میکند. برای نمونه اگر یک عضو منفرد در ماژول داشته باشیم که بخواهیم اکسپورت کنیم میتوانیم کد زیرا در ماژول moduleA.js بنویسیم:
1const num = 1;
2export default num;
زمانی که از اکسپورت پیشفرض استفاده میکنیم، نیازی به آوردن آکولاد وجود ندارد. در ادامه در فایلی که میخواهیم عضو مربوطه را ایمپورت کنیم یعنی در ماژول moduleB.js کدی مانند زیر مینویسیم:
1import num from './moduleA'
در این مورد نیز آکولاد نیامده است. دلیل این مسئله آن است که تنها یک اکسپورت پیشفرض در هر ماژول مجاز است. به طور جایگزین میتوانیم کد زیر را در ماژول moduleB.js بنویسیم:
1import {default as num} from './moduleA'
تغییر دادن نام ایمپورت و اکسپورت
اگر ماژولهای زیادی داشته باشیم و اعضای اکسپورتشده آنها نام یکسانی داشته باشند، در این صورت در زمان تلاش برای ایمپورت ماژولهای مختلف با مشکل تداخل مواجه میشویم. این مسئلهای است که باید حل شود. خوشبختانه جاوا اسکریپت یک کلیدواژه به صورت as دارد که به اما امکان میدهد اکسپورتها و ایمپورتها را تغییر نام دهیم و به این ترتیب بتوانیم از تداخل نامها در کد جلوگیری کنیم. برای استفاده از کلیدواژه as برای تغییر نام اکسپورتها، میتوانیم کدی مانند زیر در ماژول moduleA.js بنویسیم:
1export {
2 num1 as numOne,
3 num2 as numTwo
4}
سپس در ماژول moduleB.js میتوانیم آنها را با نوشتن کد زیر ایمپورت کنیم:
1import { numOne, numTwo } from './moduleA'
به طور جایگزین میتوانیم در زمان ایمپورت کردن نیز تغییر نام را انجام دهیم. به این منظور در ماژول moduleA.js کدی مانند زیر مینویسیم:
1export {
2 num1,
3 num2
4}
سپس در ماژول moduleB.js کد زیر را قرار میدهیم:
1import { num1 as numOne, num2 as numTwo } from './moduleA'
اگر تلاش کنیم که اعضا را از ماژولهایی که اعضای دارای نام یکسان دارند ایمپورت کنیم:
1import { num1, num2 } from './moduleA';
2import { num1, num2 } from './moduleB';
3import { num1, num2 } from './moduleC';
خواهیم دید که یک خطای SyntaxError ایجاد میشود. بنابراین باید نام آنها را تغییر دهیم تا ماژول بتواند اجرا شود:
1import { num1 as num1A, num2 as num2A } from './moduleA';
2import { num1 as num1B, num2 as num2B } from './moduleB';
3import { num1 as num1C, num2 as num2C } from './moduleC';
یک روش تمیزتر برای ایمپورت از چندین ماژول با اعضای دارای نام یکسان این است که همه اعضای اکسپورت شده ماژول را به صورت یک شیء ایمپورت کنیم. برای نمونه به جای نوشتن کدی مانند زیر:
1import { num1 as num1A, num2 as num2A } from './moduleA';
2import { num1 as num1B, num2 as num2B } from './moduleB';
3import { num1 as num1C, num2 as num2C } from './moduleC';
میتوانیم کدی مانند زیر بنویسیم:
1import * as moduleA from './moduleA';
2import * as moduleB from './moduleB';
3import * as moduleC from './moduleC';
سپس زیر ایمپورتها، میتوانیم کدی مانند زیر بنویسیم:
1moduleA.num1;
2moduleA.num2;
3moduleB.num1;
4moduleB.num2;
5moduleC.num1;
6moduleC.num2;
همچنین میتوانیم کلاسها را اکسپورت و ایمپورت کنیم. بنابراین اگر فایلی داشته باشیم که شامل یک یا چند کلاس مانند فایل Person.js با کلاس زیر باشد:
1class Person {
2 constructor(firstName, lastName) {
3 this._firstName = firstName;
4 this._lastName = lastName;
5 }
6 get fullName() {
7 return `${this.firstName} ${this.lastName}`
8 }
9 get firstName() {
10 return this._firstName
11 }
12 get lastName() {
13 return this._lastName
14 }
15 sayHi() {
16 return `Hi, ${this.firstName} ${this.lastName}`
17 }
18 set firstName(firstName) {
19 this._firstName = firstName;
20 }
21 set lastName(lastName) {
22 this._lastName = lastName;
23 }
24}
میتوانیم با استفاده از کد زیر آن کلاس را اکسپورت کنیم:
1export { Person };
کد فوق کلاس Person را اکسپورت میکند. برای ایمپورت کردن آن میتوانیم کدی مانند زیر بنویسیم:
1import { Person } from './person';
بارگذاری دینامیک ماژول
ماژولهای جاوا اسکریپت میتوانند به صورت دینامیک بارگذاری شوند. این وضعیت به ما امکان میدهد که ماژولها را در زمانی که به آنها نیاز داریم بارگذاری کنیم و دیگر لازم نیست همه ماژولها را در زمان اجرای اپلیکیشن بارگذاری کنیم. به این منظور باید از تابع ()import استفاده کنیم که یک promise بازگشت میدهد. هنگامی که ماژول موجود در آرگومان بارگذاری میشود، promise کامل خواهد شد. promise به یک شیء ماژول resolve میشود که میتوان از آن در کد اپلیکیشن استفاده کرد. اگر کلاس Person را در فایل Person.js داشته باشیم، در این صورت میتوانیم آن را با کد زیر به صورت دینامیک ایمپورت کنیم:
1import('./Person')
2.then((module)=>{
3 const Person = module.Person;
4 const person = new Person('Jane', 'Smith');
5 person.sayHi();
6})
همچنین میتوانیم از ساختار async و await استفاده کنیم و به این منظور میتوانیم آنها را در یک تابع قرار دهیم:
1const importPerson = async ()=>{
2 const module = await import('./Person');
3 const Person = module.Person;
4 const person = new Person('Jane', 'Smith');
5 person.sayHi();
6}
7importPerson();
چنان که میبینید، ماژولهای جاوا اسکریپت برای سازماندهی کد بسیار مفید هستند. این وضعیت به ما امکان میدهد که همه مواردی که میخواهیم در ماژولهای دیگر به آنها دسترسی داشته باشیم را اکسپورت کنیم و به این ترتیب نیاز به استفاده از متغیرهای سراسری رفع میشود. به علاوه میتوان نام اکسپورتها و ایمپورتها را تغییر داد تا از بروز تداخل در صورت ایمپورت از چندین ماژول اجتناب نمود. ضمناً همه اعضای اکسپورت شده را میتوان به صورت یکجا ایمپورت کرد و به این ترتیب کل ماژول را به صورت یک شیء به دست آورد و دیگر نیازی به ایمپورت تکتک اعضا وجود ندارند. در نهایت میتوانیم از export default تنها در صورتی که بخواهیم تنها یک عضو ماژول را اکسپورت کنیم، بهره بگیریم.
اگر این مطلب برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای JavaScript (جاوا اسکریپت)
- مجموعه آموزشهای برنامهنویسی
- آموزش جاوا اسکریپت (JavaScript)
- معرفی جاوا اسکریپت ناهمگام — به زبان ساده
- ۱۱ ترفند بسیار کاربردی جاوا اسکریپت — به زبان ساده
==
واقعا عالی توضیح داده بودین ،مفصل و لذت بخش