برای زمانبندی اجرای توابع در جاوااسکریپت ۲ روش وجود دارد.
۱. اینکه شما به طور مستقیم یک تابع را اجرا کنید. به عنوان مثال به صورت someFunction()
۲. روش دوم برنامهریزی برای اجرای تابع در زمان آینده است. مثلاً به صورت (el.addEventListener(‘click’, someFunction
اگر از حالت اول برای اجرای توابع در جاوااسکریپت استفاده کنید تابع مورد نظر به سادگی اجرا خواهد شد. این روش بسیار آسان است. اما آنچه که ما متوجه آن شدهایم این است که برخی افراد در کار با توابع با مشکلاتی روبرو هستند. بنابراین اجازه دهید نگاه دقیقتری به موضوع داشته باشیم.
قطعه کد زیر را در نظر بگیرید.
function init() { // Do initialization work const myElement = document.createElement('li'); myList.append(myElement); } init();
در قطعه کد بالا چه اتفاقی رخ داده است؟ در واقع در این کد، تابعی با نام init تعریف شده است که در داخل آن یک عنصر <li> ایجاد شده و به عنصر myList که احتمالاً در جایی دیگر از کد عملکرد خود را نشان خواهد داد، اضافه شده است. قابل ذکر است که کدهای این تابع بالافاصله پس از بارگذاری فایل اسکریپت اجرا نخواهد شد. این تابع زمانی اجرا میشود که فراخوانی شده باشد و فقط یکبار اجرا میشود. البته تمامی مواردی که تا کنون ذکر شدند موارد جدیدی نیستند و قطعا با آنها آشنا هستید.
بعضی از افراد هنگام برنامه نویسی با کدهایی مثل قطعه کد زیر به مشکل بر میخورند.
function greet() { alert('Hi there!'); } someButton.addEventListener('click', greet);
اما قسمت گیج کننده قطعه کد بالا کدام بخش است؟ به این بخش از کد توجه کنید.
someButton.addEventListener('click', greet);
آیا در این قسمت نوشتن پارانتز برای greet از یاد نرفته است؟ آیا نباید قطعه کد به صورت زیر باشد؟
someButton.addEventListener('click', greet());
نه مطلقاً اینگونه نیست. چرا؟
زیرا اگر پارانتز به آن اضافه شده و به صورت greet() نوشته شود، به محض اجرای جاوااسکریپت اجرا خواهد شد. درحالی که آنچه ما میخواهیم این است که با یک بار کلیک بر روی دکمه someButton تابع اجرا شود. این یک چیز متفاوت است.
در موارد استاندارد، ما دستورات جاوااسکریپت را درون توابع قرار میدهیم. یعنی همان کاری که در نخستین مثال این مقاله انجام دادیم.
function init() { // Do initialization work const myElement = document.createElement('li'); myList.append(myElement); } init();
درحالت دوم ما نمیخواهیم تابع را مستقیما اجرا کنیم و مایل هستیم تابع به صورت غیرمستقیم اجرا شود. در واقع میخواهیم به جاوااسکریپت / مرورگر بگوییم، هرگاه اتفاق خاصی مانند فشردن دکمه از طرف کاربر رخ داد، تابع greet اجرا شود. از این رو نباید به تابع greet پارانتز اضافه کنیم. زیرا با انجام این کار تابع فورا فراخوانی میشود.
با استفاده از این دستور:
someButton.addEventListener('click', greet);
در واقع ما این تابع را به عنوان پارامتر دوم تابع addEventListener انتخاب میکنیم و سپس مرورگر با استفاده از کدهای جاوااسکریپت آن را برای ما فراخوانی میکند. اگر کد را به صورت زیر بنویسید:
someButton.addEventListener('click', greet());
greet را به عنوان پارامتری برای addEventListener در نظر نگرفتهاید و نتیجه نهایی منجر به اجرا شدن مستقیم greet شده است.
نتیجه نهایی چیست؟
در واقع نتیجه نهایی بستگی به نتیجه تابع دارد. در اینجا چیزی تعریف نشده و نتیجهای بازگردانده نمیشود. اما اگر فراخوانی نتیجهای در بر داشته باشد، پس از اجرای تابع، اتفاق متفاوتی خواهد افتاد.
بسیار خب. اما اگر تابع greet مانند قطعه کد زیر بود، چه میشد؟
function greet(name) { alert('Hi ' + name); }
greet یک پارامتر (name) میخواهد و ما هم در حال حاضر greet را به یک دکمه مثل مورد زیر نشان داده و وابسته کردهایم.
someButton.addEventListener('click', greet);
چگونه مرورگر / جاوااسکریپت همانطور که تاکنون آموختهایم این تابع را اجرا خواهد کرد، درحالی که میدانیم مقداری با عنوان name باید به تابع داده شود؟
پاسخ اینگونه است: در حال حاضر اگر روی دکمه کلیک کنید، خروجی به صورت Hi undefined برای شما مشخص میشود و آنچه مد نطر ما است، نمایش داده نمیشود. برای حل این موضوع ۲ راه حل وجود دارد.
someButton.addEventListener('click', function() { greet('Masood'); // 'Hi Masood' });
someButton.addEventListener('click', greet.bind(null, 'Masood')); // 'Hi Masood'
بگذارید با راه حل اول شروع کنیم.
در آرگومان دوم تابع addEventListener، ما یک تابع anonymous ایجاد کردهایم. وقتی کدهای جاوااسکریپت به این خط میرسد، بلافاصله اجرا نمیشود، زیرا ما پس از تعریف یک تابع anonymous پارانتزی اضافه نکردیم. این تابع زمانی اجرا میشود که بر روی دکمه کلیک شود. این راهحل ۱ بود اما اجازه دهید روی راهحل ۲ تمرکز کنیم:
در اینجا ما از متد bind() استفاده میکنیم که مخصوص “جاوااسکریپت” ساخته شده است. به طور دقیق میتوان گفت که در جاوااسکریپت، هر تابع میتواند یک آبجکت باشد. پس این نکته مهم را به خاطر بسپارید.
اما متد bind() چه کاری انجام میدهد؟ این متد تابعی را برای فراخوانی در آینده آماده میسازد و این امکان را به شما میدهد که از قبل، آرگومانهای تابعی را که در آینده اجرا خواهد شد، فراخوانی کنید. همچنین میتوانید کلمه کلیدی this را طوری تعریف کنید که به آن تابع ارجاع شود.
زمانی که ما از bind به صورت زیر استفاده میکنیم:
someButton.addEventListener('click', greet.bind(null, 'Masood')); // 'Hi Masood'
به جاوااسکریپت میگوییم که this باید null باشد و غیر از آن مقدار متفاوتی به خود نگیرد. همچنین اولین آرگومان ارسال شده برای greet، هنگام فراخوانی باید Masood باشد.
اینگونه درنظر بگیرید که نخستین پارامتر bind همیشه کلمه کلیدی this است و هر پارامتر دیگری پس از آن بیاید، به عنوان آرگومان ورودی تابع معرفی و فراخوانی خواهد شد.
بنابراین اولین پارامتر تابع فراخوانی شده، سپس دومین آرگومان مربوط به bind بدست خواهد آمد. پارامتر دوم تابع نیز از طریق فراخوانی آرگومان سوم برای bind تعریف خواهد شد. با استفاده از این روش، تضمین میکنیم که در هنگام فراخوانی تابع greet به عنوان یک مقدار در آینده ( توسط مرورگر / جاوااسکریپت) مقدار Masood دریافت خواهد شد.
این به شما بستگی دارد که برای اجرای توابع در جاوااسکریپت کدام یک از رویکردهای گفته شده را ترجیح دهید. قطعا انتخاب این موضوع به روش حل مسئله بستگی دارد.
[button class=”github-btn” href=”http://frontcast.ir/become-a-javascript-developer”]پادکست شماره ۵: تبدیل شدن به توسعه دهنده جاوااسکریپت[/button]
دیدگاهها:
sjln
شهریور 4, 1399 در 4:21 ب.ظ
و بالعکس اگر قرار هست همه توابع اجرا بشن همون اول، پس چرا وقتی به حالت دوم یعنی حالت صحیح اجرا میکنیم، اون توابع قبل از کلیک اجرا نمیشن؟ این موضوع خیلی برای من گنگ هست!
sjln
شهریور 4, 1399 در 2:27 ب.ظ
وقت بخیر. من یه موضوع رو نمیتونم درک کنم دلیلش رو. شما فرمودید که توی این کد:
.addEventListener(‘click’,setActive(todo.id))
تابع setActive هم اجرا میشه چون جاوااسکریپت زبان مفسر هست. اما سوال من اینجا هست که این خط کد، مگر تعریفش این نیست که در صورت رخ دادن ایونت که اینجا کلیک مد نظر هست، تابعی که ذکر میشه اجرا بشه؟ پس چرا باز هم اجرا میشه؟ وقتی کلیک رو تعریف میکنیم، یعنی نمیخوایم حالت عادی اجرا بشه میخوایم وقتی کلیک شد اجرا شه!
مسعود صدری
شهریور 4, 1399 در 5:36 ب.ظ
این تابع به دلیل وجود پرانتزها درست در زمان تفسیر کد اجرا میشه.
متد addEventListener صرفا یک ایونت برای این تابع اضافه میکنه اما نحوه اجرا رو تعیین نمیکنه.
فرقی نداره شما تابع رو به چه صورتی و با چه ایونتی بنویسید، اگر پرانتز باز و بسته وجود داشته باشه بلافاصله قرار هست فراخوانی بشه.
لطفا ویدیو رو دوباره ببینید اگر باز هم براتون مبهم بود توی واتساپ یا تلگرام بهم مسیج بدید تا توضیح بدم خدمتتون.
فرهاد
خرداد 8, 1399 در 1:50 ب.ظ
سلام،
راه حل سوم هم میتونه بصورت زیر باشه:
در ایونت on click المنت button
on click=”setActive(${todo.id})
در اینصورت با اینکه در ایونت on click داریم تابع را با پارانتز می نویسیم اما در واقع داریم رفرنس میدیم (برخلاف حالت های قبلی) درسته؟
مسعود صدری
تیر 28, 1399 در 11:55 ب.ظ
سلام
در جاوااسکرسپت برای استفاده از مقادیر متغیر در یک رشته نمیتونیم از کاراکتر $ استفاده کنیم.
برای این کار از Template String و کاراکتر {} استفاده میکنیم.