تابع سفارشی در جاوا اسکریپت – راهنمای کاربردی


اگر پیگیر نوشتههای ما در این سری مطالب راهنمای عملی جاوا اسکریپت بوده باشید، احتمالاً تاکنون متوجه شدهاید که تا به اینجا اکثر مطالب طرح شده ما علیرغم نام این دوره بیشتر پیرامون مباحث نظری بوده است. اما در این مقاله قصد داریم با مبانی عملی نوشتن تابعهای سفارشی نیز آشنا شویم. در این مسیر برخی جزییات مفید که هنگام کار با این تابعها مورد نیاز خواهد بود را نیز بررسی میکنیم.
پیشنیازها
- سواد ابتدایی رایانه
- درکی مقدماتی از HTML و CSS
- آشنایی با مبانی اولیه جاوا اسکریپت و مطلب قبلی ما در مورد «مفهوم و کاربرد تابع در جاوا اسکریپت»
هدف این مقاله ارائه عملی مراحل نوشتن تابعهای سفارشی و توضیح چند موضوع مفید مرتبط با این زمینه است.
با کلیک روی لینک زیر میتوانید قسمت قبلی این مجموعه مطلب را مطالعه کنید:
یادگیری عملی: نوشتن اولین تابع سفارشی
ما قصد داریم در ادامه یک تابع سفارشی بنویسیم که آن را ()displayMessage مینامیم. این تابع یک کادر پیام سفارشی روی صفحه وب نمایش خواهد داد و به عنوان یک جایگزین سفارشیسازی شده برای تابع ()alert داخلی مرورگر عمل میکند. ما این تابع را قبلاً دیدهایم؛ اما یک بار دیگر آن را یادآوری میکنیم. کد زیر را در کنسول جاوا اسکریپت مرورگر وارد کنید:
1alert('This is a message');
تابع alert یک آرگومان میگیرد و آن رشتهای است که در کادر پیام نمایش خواهد یافت. با تغییر دادن این رشته میتوانید متن پیام را عوض کنید. تابع alert محدود است و شما میتوانید پیام را عوض کنید؛ اما نمیتوانید به سادگی چیزهای دیگر مانند رنگ، آیکون، یا هر چیز دیگر را تغییر دهید. ما تابع نمایش پیامی مینویسیم که از تابع alert جذابتر باشد.
دقت کنید که تابعی که ما مینویسیم در همه مرورگرهای مدرن به خوبی کار خواهد کرد؛ اما سبکبندی ظاهری آن ممکن است در برخی مرورگرهای قدیمی کمی دچار بههمریختگی شود. توصیه میکنیم این تمرین را در مرورگر مدرنی مانند فایرفاکس، اپرا یا کروم اجرا کنید.
تابع ابتدایی
ابتدا کار خود را با طراحی یک تابع ابتدایی آغاز میکنیم.
نکته: بر اساس قرارداد نامگذاری تابعها باید از همان قواعد مطرح شده در قراردادهای نامگذاری متغیرها پیروی کنید. بدین ترتیب میتوان آنها را به سادگی از هم متمایز کرد، چون تابعها در انتهای خود یک جفت پرانتز دارند، اما متغیرها چنین چیزی ندارند.
برای طراحی یک تابع ابتدایی، در گام اول کد زیر را در فایلی به نام function-start.html روی سیستم خود قرار دهید:
1<!DOCTYPE html>
2<html>
3 <head>
4 <meta charset="utf-8">
5 <title>Function start</title>
6 <style>
7 .msgBox {
8 position: absolute;
9 top: 50%;
10 left: 50%;
11 transform: translate(-50%,-50%);
12 width: 200px;
13 background: #eee;
14 }
15 .msgBox p {
16 line-height: 1.5;
17 padding: 10px 20px;
18 color: #333;
19 }
20 .msgBox button {
21 background: none;
22 border: none;
23 position: absolute;
24 top: 0;
25 right: 0;
26 font-size: 1.1rem;
27 color: #aaa;
28 }
29 </style>
30 </head>
31 <body>
32 <button>Display message box</button>
33
34 <script>
35
36 </script>
37 </body>
38</html>
همان طور که میبینید کدهای HTML ساده هستند و تنها یک body با یک دکمه در آن تعریف شده است. همچنین برخی کدهای CSS در آن ارائه کردهایم که ظاهر کادر پیام ما را تعیین میکند و یک عنصر <sctipt> خالی نیز وجود دارد که باید کد جاوا اسکریپت خود را در آن قرار دهیم.
سپس کد زیر را درون عنصر <script> قرار میدهیم:
1function displayMessage() {
2
3}
کار خود را با نوشتن کلیدواژه function آغاز میکنیم که به این معنی است که میخواهیم یک تابع تعریف کنیم. متعاقب آن نام تابعی که میخواهیم داشته باشیم را میآوریم و سپس یک جفت پرانتز و یک جفت آکولاد میآید. هر پارامتری که بخواهیم به تابع خود بفرستیم درون پرانتزها تعریف میشود و کدی که باید در زمان فراخوانی تابع اجرا شود نیز درون آکولادها قرار میگیرد.
در نهایت کد زیر را درون آکولادها اضافه کنید:
1var html = document.querySelector('html');
2
3var panel = document.createElement('div');
4panel.setAttribute('class', 'msgBox');
5html.appendChild(panel);
6
7var msg = document.createElement('p');
8msg.textContent = 'This is a message box';
9panel.appendChild(msg);
10
11var closeBtn = document.createElement('button');
12closeBtn.textContent = 'x';
13panel.appendChild(closeBtn);
14
15closeBtn.onclick = function() {
16 panel.parentNode.removeChild(panel);
17}
شاید این کد به نظرتان طولانی بیاید، بنابراین در ادامه به توضیح خط به خط آن میپردازیم.
در خط اول از یک تابع DOM API به نام ()document.querySelector برای انتخاب عنصر <html> استفاده میکنیم و ارجاعی به آن در یک متغیر به نام html ذخیره میکنیم. بدین ترتیب میتوانیم در ادامه کارهایی مانند زیر را انجام دهیم:
1var html = document.querySelector('html');
در بخش بعدی از تابع DOM API دیگری به نام ()Document.createElement برای ایجاد یک عنصر <div> و ذخیرهسازی یک ارجاع به یک متغیر به نام panel استفاده میکنیم. این عنصر کانتینر بیرونی کادر پیام ما خواهد بود.
سپس از یک تابع DOM API دیگر به نام ()Document.createElement برای تعیین یک خصوصیت کلاس روی پنل خود استفاده میکنیم و مقدار msgbox به آن میدهیم. این کار برای آسانتر شدن سبکبندی عنصر صورت میگیرد. اگر به CSS صفحه نگاه کنید، میبینید که از یک سلکتور کلاس msgbox. برای سبک دهی به کادر پیام خود و محتوای آن استفاده کردهایم.
در نهایت یک تابع DOM به نام ()Node.appendChild را روی متغیر html که قبلاً ذخیره کردیم فراخوانی میکنیم که یک عنصر را درون عنصر دیگری به عنوان فرزند آن به صورت تو در تو قرار میدهد. ما پنل <div> را به عنوان فرزند یک عنصری که میخواهیم به عنصر <html> الحاق کنیم تعیین میکنیم. این کار به این دلیل صورت میگیرد که این عنصر به صورت مستقل روی صفحه ظاهر نشود و از این رو باید مکانی که در آن قرار میگیرد را تعیین کنیم.
1var panel = document.createElement('div');
2panel.setAttribute('class', 'msgBox');
3html.appendChild(panel);
در دو بخش بعدی از همان تابعهای ()createElement و ()appendChild که قبلاً دیدیم برای ایجاد دو عنصر به صورت یک <p> و یک <button> استفاده میکنیم و آنها را در صفحه به صورت فرزندان پنل <div> درج میکنیم. ما از خصوصیت Node.textContent آنها استفاده میکنیم و محتوای متنی عنصر را درون یک پاراگراف نمایش میدهیم و یک علامت X نیز درون دکمه قرار میدهیم. این دکمه در مواردی که کاربر میخواهد کادر پیام را ببندد کلیک/فعال میشود.
1var msg = document.createElement('p');
2msg.textContent = 'This is a message box';
3panel.appendChild(msg);
4
5var closeBtn = document.createElement('button');
6closeBtn.textContent = 'x';
7panel.appendChild(closeBtn);
در نهایت از یک دستگیره رویداد به نام GlobalEventHandlers.onclick طوری استفاده میکنیم که وقتی دکمه کلیک شد، کدی که برای حذف پنل از صفحه نوشتهایم اجرا شود و کادر پیام بسته شود.
به طور خلاصه دستگیره onclick خصوصیت آمادهای روی دکمه (و در واقع هر عنصری روی صفحه) است که میتوان آن را به یک تابع اختصاص داد که هنگام کلیک شدن دکمه اجرا میشود. در مقالههای مربوط به رویدادها در ادامه این سری مقالات آموزش عملی جاوا اسکریپت در این مورد بیشتر صحبت خواهیم کرد. ما دستگیره onclick را برابر با یک تابع «بینام» (anonymous) قرار میدهیم که شامل کدی است که هنگام کلیک شدن دکمه اجرا میشود. آن خط کد درون تابع بینام، از تابع DOM API به نام ()Node.removeChild برای تعیین فرزند خاصی از عناصر صفحه که میخواهیم حذف شود استفاده خواهد شد. در این مورد این عنصر پنل <div> است.
1closeBtn.onclick = function() {
2 panel.parentNode.removeChild(panel);
3}
اساساً این بلوک از کد یک بلوک HTML ایجاد میکند که مطابق انتظار ما نمایش مییابد و در صفحه قرار میگیرد:
1<div class="msgBox">
2 <p>This is a message box</p>
3 <button>x</button>
4</div>
بدین ترتیب توضیح کد تابع سفارشی ما پایان مییابد، اما اگر دقیقاً متوجه نشدید که هر بخش از کد چه کاری انجام میدهد، جای نگرانی نیست، زیرا در این مرحله صرفاً روی ساختار و کاربرد تابع متمرکز شدهایم؛ اما در ادامه میخواهیم نکته جالبی در خصوص این مثال مطرح کنیم.
فراخوانی تابع
اینک تعریف تابع خود را درون عنصر <script> به طور کامل نوشتهایم؛ اما این تابع هنوز هیچ کاری انجام نداده است. خط کد زیر را در ادامه تعریف تابع وارد کنید تا بتوانید آن را فراخوانی کنید:
1displayMessage();
این کد تابع را فراخوانی و آن را بیدرنگ اجرا میکند. زمان که کد خود را ذخیره کرده و صفحه را مجدداً در مرورگر بارگذاری کنید، یک کادر پیام کوچک را مشاهده میکنید که تنها یک بار نمایش مییابد. چون ما آن را فقط یک بار فراخوانی میکنیم.
در ادامه، بخش «ابزارهای توسعهدهنده مرورگر» (Browser Developer Tools) را باز روی صفحه مثال خودمان باز کنید و به کنسول جاوا اسکریپت رفته و این خط کد را مجدداً وارد کنید. مشاهده میکنید که کادر پیام دوباره نمایش مییابد. بنابراین نکته جالبی که از آن صحبت کردیم تابع با استفاده مجددی است که اینک میتوانیم هر زمان بخواهیم آن را فراخوانی کنیم.
اما در اکثر موارد میخواهیم که این کادر پیام در پاسخ به یک عمل کاربر یا یک کنش سیستمی ظاهر شود. در اپلیکیشنهای واقعی چنین کادر پیامی احتمالاً در پاسخ به ارائه دادههای جدید، بروز یک خطا و یا هنگامیکه کاربر پروفایل خود را حذف کند، ظاهر میشود. همچنین در مواردی که یک مخاطب جدید اضافه شود یا عملیاتی با موفقیت پایان یابد چنین کادرهایی نمایش مییابند.
در این دمو یک کادر پیام به دست میآوریم که وقتی کاربر روی دکمه کلیک کند نمایش مییابد.
خط قبلی که اضافه کردید را حذف کنید. سپس دکمه را انتخاب کرده و در متغیری یک ارجاع به آن ذخیره کنید. خط زیر را به بخش بالای تعریف تابع در کد خود اضافه کنید:
1var btn = document.querySelector('button');
در نهایت کد زیر را زیر خط قبلی اضافه کنید:
1btn.onclick = displayMessage;
به روشی مشابه ...closeBtn.onclick درون تابع، در ادامه کدهایی را در پاسخ به کلیک شدن دکمه فراخوانی میکنیم. اما در این مورد به جای فراخوانی یک تابع بینام که شامل کدی است، یک تابع بانام را مستقیماً فراخوانی میکنیم.
صفحه را ذخیره و رفرش کنید تا یک کادر پیام داشته باشید که وقتی روی دکمه کلیک میکنید ظاهر میشود.
شاید تعجب کنید که چرا پس از نام تابع، پرانتزها را نیاوردهایم. دلیل این امر آن است که ما نمیخواهیم تابع را بیدرنگ فراخوانی کنیم و فراخوانی تنها پس از این که دکمه کلیک شد، صورت میپذیرد. اگر کد را به صورت زیر تغییر دهید:
1btn.onclick = displayMessage();
و صفحه را ذخیره و بارگذاری مجدد کنید، میبینید که کادر پیام، بدون این که دکمه را کلیک کنید نیز نمایش خواهد یافت. بنابراین پرانتزها در این چارچوب در برخی موارد «عملگر فراخوانی تابع» نیز نامیده میشوند. ما تنها زمانی از آنها استفاده میکنیم که بخواهیم تابع را بیدرنگ در دامنه جاری اجرا کنیم. به همین ترتیب کد درون تابع بینام نیز بیدرنگ اجرا نمیشد، زیرا در دامنه تابع قرار دارد.
اگر این تمرین اخیر را اجرا کرده باشید، مطمئن شوید که پیش از ادامه، تغییر آخر را به حالت قبلی بازمیگردانید.
بهبود تابع با استفاده از پارامترها
چنان که مشخص است تابع ما در حال حاضر چندان مفید نیست، زیرا ما احتمالاً نمیخواهیم هر بار پیام یکسانی را نمایش دهیم. میتوان با افزودن برخی پارامترها که امکان فراخوانی تابع با گزینههای مختلف را فراهم میسازند آن را بهبود داد.
قبل از هر چیز خط اول تابع را از حالت زیر:
1function displayMessage() {
به صورت زیر بهروزرسانی کنید:
1function displayMessage(msgText، msgType) {
اینک زمانی که تابع فراخوانی شود، میتوانیم دو مقدار متغیر درون پرانتزها ارائه کنیم که پیامی که درون کادر پیام نمایش خواهد یافت و نوع آن را تعیین میکند.
برای استفاده از پارامتر نخست باید خط زیر را درون تابع:
1msg.textContent = 'This is a message box';
به صورت زیر بهروزرسانی کنیم:
1msg.textContent = msgText;
در ادامه باید فراخوانی تابع را طوری تغییر دهیم که شامل متن پیام سفارشی باشد. بدین منظور خط زیر را در کد:
1btn.onclick = displayMessage;
به صورت زیر تغییر دهید:
1btn.onclick = function() {
2 displayMessage('Woo, this is a different message!');
3};
اگر بخواهیم پارامترها را درون پرانتزها برای فراخوانی تابع خود مورد اشاره قرار دهیم در این صورت نمیتوانیم آن را به صورت مستقیم فراخوانی کنیم و باید آن را درون یک تابع بینام به طرزی قرار دهیم که در دامنه بیدرنگ قرار نگیرد و از این رو به صورت بیدرنگ فراخوانی نشود. اینک این تابع تا زمانی که دکمه کلیک نشود، فراخوانی نخواهد شد.
صفحه را بارگذاری مجدد کنید تا ببینید که کد ما به درستی کار میکند؛ به جز این که در حال حاضر میتوانید پیام مورد نظر خود را درون پارامتر تابع تغییر دهید تا در کادر پیام نمایش یابد.
یک پارامتر پیچیدهتر
در پارامتر بعدی تابع سفارشیمان قصد داریم کار پیچیدهتری انجام دهیم و بسته به این که پارامتر msgType چگونه تنظیم شده باشد، تابع ما آیکون و رنگ پسزمینه متفاوتی را نمایش دهد.
به این منظور ابتدا آیکونهای مورد نیاز زیر را روی سیستم خود و در یک پوشه جدید به نام icons در همان مسیری که فایل HTML تان قرار دارد، ذخیره کنید:


سپس بخش CSS را درون فایل HTML خود پیدا کنید و تغییراتی در آن ایجاد کنید تا آیکونها نمایش یابند. ابتدا عرض msgbox. را از مقدار زیر:
1width: 200px;
به صورت زیر تغییر دهید:
1width: 242px;
سپس خطوط زیر را درون قاعده { ... } msgBox اضافه کنید:
1padding-left: 82px;
2background-position: 25px center;
3background-repeat: no-repeat;
اینک میتوانیم کد خود را به تابع ()displayMessage اضافه کنیم تا نمایش آیکونها را بر عهده بگیرد. بلوک کد زیر را درست بالای آکولاد پایانی ({) تابع خود قرار دهید:
1if (msgType === 'warning') {
2 msg.style.backgroundImage = 'url(icons/warning.png)';
3 panel.style.backgroundColor = 'red';
4} else if (msgType === 'chat') {
5 msg.style.backgroundImage = 'url(icons/chat.png)';
6 panel.style.backgroundColor = 'aqua';
7} else {
8 msg.style.paddingLeft = '20px';
9}
بدین ترتیب پارامتر msgType به صورت warning تعیین شده است و آیکون هشدار نمایش مییابد. رنگ پسزمینه نیز به صورت قرمز تنظیم خواهد شد. اگر نوع پیام به صورت chat تعیین شده بود، آیکون گفتگو نمایش مییافت و رنگ پسزمینه نیز به صورت آبی روشن تعیین میشد. اگر پارامتر msgType کلاً تعیین نشود (یا چیز متفاوتی باشد) در این صورت بخش { ... } else کد اجرا میشود و پاراگراف دارای حاشیهگذاری پیشفرض خواهد بود و هیچ آیکونی نمایش نمییابد و رنگ پسزمینه نیز نمایش داده نمیشود. بدین ترتیب اگر هیچ پارامتر msgType ارائه نشود، یک حالت پیشفرض ایجاد میشود و این بدان معنی است که این پارامتر اختیاری است.
در ادامه کد خود را تست میکنیم. به این منظور فراخوانی ()displayMessage را از وضعیت زیر:
1displayMessage('Woo، this is a different message!');
به صورت زیر تغییر میدهیم:
1displayMessage('Your inbox is almost full — delete some mails'، 'warning');
2displayMessage('Brian: Hi there، how are you today?'،'chat');
اینک میبینید که تابع (نه چندان) کوچک ما به چه تابع مفیدی تبدیل شده است.
اگر در هر بخش از کد خود با مشکلی مواجه شدید، میتوانید از نسخه تکمیل شده آن که در زیر ارائه شده است، استفاده کنید:
1<!DOCTYPE html>
2<html>
3 <head>
4 <meta charset="utf-8">
5 <title>Function stage 4</title>
6 <style>
7 .msgBox {
8 position: absolute;
9 top: 50%;
10 left: 50%;
11 transform: translate(-50%,-50%);
12 width: 242px;
13 border-radius: 10px;
14 background-color: #eee;
15 background-image: linear-gradient(to bottom, rgba(0,0,0,0), rgba(0,0,0,0.1));
16 }
17 .msgBox p {
18 line-height: 1.5;
19 padding: 10px 20px;
20 color: #333;
21 padding-left: 82px;
22 background-position: 25px center;
23 background-repeat: no-repeat;
24 }
25 .msgBox button {
26 background: none;
27 border: none;
28 position: absolute;
29 top: 0;
30 right: 0;
31 font-size: 1.1rem;
32 color: #aaa;
33 }
34 </style>
35 </head>
36 <body>
37 <button>Display message box</button>
38
39 <script>
40 var btn = document.querySelector('button');
41 btn.onclick = function() {
42 displayMessage('Brian: Hi there, how are you today?','chat');
43 };
44 function displayMessage(msgText,msgType) {
45 var html = document.querySelector('html');
46 var panel = document.createElement('div');
47 panel.setAttribute('class','msgBox');
48 html.appendChild(panel);
49 var msg = document.createElement('p');
50 msg.textContent = msgText;
51 panel.appendChild(msg);
52 var closeBtn = document.createElement('button');
53 closeBtn.textContent = 'x';
54 panel.appendChild(closeBtn);
55 closeBtn.onclick = function() {
56 panel.parentNode.removeChild(panel);
57 }
58 if(msgType === 'warning') {
59 msg.style.backgroundImage = 'url(icons/warning.png)';
60 panel.style.backgroundColor = 'red';
61 } else if(msgType === 'chat') {
62 msg.style.backgroundImage = 'url(icons/chat.png)';
63 panel.style.backgroundColor = 'aqua';
64 } else {
65 msg.style.paddingLeft = '20px';
66 }
67 }
68 </script>
69 </body>
70</html>
سخن پایانی
بدین ترتیب به پایان این بخش از سری مقالات جامع راهنمای عملی جاوا اسکریپت رسیدیم. در این مقاله فرایند کامل ساخت یک تابع سفارشی عملیاتی را با هم مرور کردیم که با اندکی تمیزکاری بیشتر میتواند در یک پروژه واقعی مورد استفاده قرار گیرد.
در بخش بعدی این سری مقالات، بحث تابعهای جاوا اسکریپت را با معرفی یک مفهوم ضروری مرتبط دیگر به نام «مقادیر بازگشتی» جمعبندی خواهیم کرد.
برای مطالعه قسمت بعدی این مجموعه مطلب روی لینک زیر کلیک کنید:
اگر این مطلب برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای طراحی و برنامه نویسی وب
- آموزش تعریف توابع در جاوا اسکریپت (JavaScript)
- مجموعه آموزشهای برنامهنویسی
- آموزش جاوا اسکریپت (JavaScript)
- تابع های Arrow در جاوا اسکریپت — از صفر تا صد
- آموزش JavaScript ES6 (جاوااسکریپت)
- تابع های جاوا اسکریپت — راهنمای جامع
==