در جاوااسکریپت متدها و توابع higher orderای وجود دارد که یک تابع را به عنوان آرگومان میپذیرند. این توابع که به عنوان آرگومان برای توابع دیگر مورد استفاده قرار میگیرند توابع callback نامیده میشوند. در این مقاله قصد داریم تا با نوشتن یک نمونه تابع callback، با مفهوم و نحوه استفاده از آن آشنا شویم. همینطور در دوره آموزش جاوااسکریپت – مفاهیم پیشرفته این توابع به شکل کامل مورد بررسی قرار گرفته است.
callback تابعی است که به عنوان آرگومان یک تابع دیگر ارسال میشود.
یعنی این که تابع parent معمولاً از هر نوع تابعی میتواند استفاده کند. اما تابع callback، برای استفاده در یک مورد خاص (یا تعداد محدودی از موارد) است که در آن تابع parent مورد استفاده قرار میگیرد.
تابع callback مانند هر تابع دیگری در جاوااسکریپت ساخته میشود:
function callbackFunction () { }
تفاوت بین تابع callback و توابع دیگر فقط در نحوه استفاده از آن است. یک تابع callback به طور خاص به این منظور ساخته شده است تا به عنوان آرگومان یک تابع دیگر استفاده شود.
function anyFunction(fun) { // ... fun(a, b, c); //... } anyFunction(callbackFunction);
بنابراین برای ایجاد یک callbackFunction
باید بدانیم که تابع parent چگونه از تابع callback استفاده میکند، چه آرگومان هایی را میگیرد و به چه ترتیبی آنها را ارسال میکند.
یک تابع higher order که در زبان جاوااسکریپ وجود دارد متد every
میباشد. این متد یک متد آرایه است و از یک فراخوانی برای بررسی اینکه آیا تمام عناصر موجود در آرایه یک تست خاصی را پشت سر گذاشتهاند یا نه استفاده میکند.
با نگاهی به مستندات مربوط به متد every میتوانیم ببینیم که callback سه آرگومان ارسال میکند: یک المنت از آرایه، ایندکس آن المنت و کل آرایه.
بنابراین ظاهر تابع callback چیزی شبیه به این خواهد بود:
function callbackFunction(element, index, array) { // do something }
توابع callback به همان اندازه که ما به آنها نیاز داریم میتوانند ساده یا پیچیده باشند.
فرض کنید با آرایهای از رشتهها کار میکنیم. باید بررسی کنیم که آرایه فقط شامل رشتههایی باشد که دقیقاً سه کاراکتر دارند، حروف بزرگ هستند، همه حروف مختلف را دربرمیگیرند و در داخل آرایه تکرار نمیشوند.
این یک مثال بسیار پیچیده است، اما تمرین بسیار خوبی به شمار میآید.
وقتی یک تابع ایجاد میکنیم که موارد زیادی بررسی میکند، میتوانیم در هر زمان یک شرط را مورد بررسی قرار دهیم.
شرط اول این است که عنصر یک رشته باشد، بنابراین آن را اضافه میکنیم:
function callbackFunction(element, index, array) { // check that element is a string const isNotString = typeof element !== "string"; // if it's not, end function if (isNotString) {return;} }
سپس رشتهها باید همگی شامل ۳ کاراکتر که از حروف بزرگ تشکیل میشوند باشند.
میتوانیم این سه شرط را به صورت جداگانه بررسی کنیم و یا این که میتوانیم این کار را با یک عبارت منظم که دقیقاً آن سه مورد را بررسی میکند انجام دهیم.
چنین عبارت منظمی مانند این خواهد بود: /^[A-Z]{3}$/
.
^
در ابتدا و $
در پایان anchor هستند. اینها میگویند که رشته باید دقیقاً به همین شکل شروع شده و به پایان برسد. و اگر از هر دو استفاده کنیم در واقع رشته را محدود کردهایم تا فقط و دقیقاً یک الگو را در عبارت منظم داشته باشد.[A-Z]
یک کلاس کاراکتر است که با هر کاراکتری از A
تا Z
مطابقت دارد، بنابراین همه حروف بزرگ را شامل میشود.{۳}
یک شمارنده است و میگوید که مورد قبلی باید دقیقاً سه بار متوالی با این الگو مطابقت داشته باشد.عبارت منظم توضیح داده شده در بالا معادل این عبارت منظم است:/^[A-Z][A-Z][A-Z]$/
.
در این حالت به جای شمارنده {۳}
کلاس [A-Z]
را سه مرتبه نوشتهایم.
اکنون آن را به کد اضافه میکنیم:
function callbackFunction(element, index, array) { // check that element is a string const isNotString = typeof element !== "string"; // if it's not, end function if (isNotString) { return; } // check that string is 3 characters long and only uppercase letters const isItThreeUpperCaseLetters = /^[A-Z]{3}$/.test(element); // otherwise, end function if (!isItThreeUpperCaseLetters) { return; } }
اگر نخواهیم از عبارات منظم استفاده کنیم، میتوانیم این کار بدون آنها نیز انجام دهیم که در ادامه آن را بررسی کردهایم.
سپس در مرحله بعد باید بررسی کنیم که آیا کاراکترها متفاوت هستند یا خیر.
سه کاراکتر وجود دارد که برای بررسی آنها میتوانیم از این روش استفاده کنیم: element[0] !== element[1] && element[0] !== element[2] && element[1] !== element[2]
.
همچنین میتوانیم این کار را با حلقه نیز انجام دهیم. به عنوان مثال:
// with the outer loop, you get j, the first index to compare for (let j = 0; j++; j < element.length) { // with the inner loop you get k, the second index to compare for (let k = j+1; k++; k < element.length) { // you compare the element at index j with the element at index k if (element[j] === element[k]) { // if they are equal return to stop the function return; } } }
حلقهای که در مثال بالا نوشیم با هر lengthای کار میکند و نیازی به بازنویسی آن برای موقعیتهای مختلف ندارد.
در تکرار اول j=0
و k=1
است، بنابراین اولین مقایسه به شکل element[0] === element[1]
میباشد. سپس k افزایش پیدا کرده و j=0
و k=2
میشود، بنابراین element[0] === element[2]
میشود.
در این مرحله حلقه داخلی متوقف میشود و حلقه بیرونی (حلقهای که j
دارد) به تکرار بعدی میرود. این بار j=1
و حلقه داخلی از k=j+1
شروع میشود، بنابراین در k=2
داریم element[1] === element[2]
.
اکنون حلقه داخلی به پایان رسیده است، حلقه بیرونی از j=1
به j=2
میرود اما این بار حلقه داخلی شروع نمیشود زیرا k = j+1 = 3
است و از شرط k < element.length
حلقه عبور نمیکند.
function callbackFunction(element, index, array) { // check that element is a string const isNotString = typeof element !== "string"; // if it's not, end function if (isNotString) { return; } // check that string is 3 characters long and only uppercase letters const isItThreeUpperCaseLetters = /^[A-Z]{3}$/.test(element); // otherwise, end function if (!isItThreeUpperCaseLetters) { return; } // check if all characters are different const allDifferentCharacters = element[0] !== element[1] && element[0] !== element[2] && element[1] !== element[2]; // if not, return to stop the function if (!allDifferentCharacters) { return; } }
سپس آخرین چیزی که باید آن را بررسی کنیم این است که داخل آرایه رشتههای تکراری نداشته باشیم.
میتوانیم از indexOf
استفاده کنیم تا بررسی کنیم که آیا مورد فعلی اولین بار میباشد که element
در داخل آرایه دیده شده است یا خیر. برای انجام این کار باید به آرایه ارجاع دهیم. ما این را داریم، پارامتر array
یکی از آرگومانهایی است که به تابع callback ارسال میشود.
اگر این اولین باری باشد که رشته در آرایه وجود دارد، خروجی indexOf
مشابه index
خواهد بود.
پس اگر مقدار array.indexOf(element) === index
برابر با true
باشد، به این معنی است که element
برای اولین بار در آرایه در index
وجود دارد. اگر false
باشد، یعنی یک رشته یکسان قبل از آن در آرایه وجود دارد.
در ادامه این مورد را هم به کد خود اضافه میکنیم و و اگر رشته مورد نظر ما از تمامی شرطها عبور کرده باشد تابع میتواند در انتها مقدارد true
برگرداند.
function callbackFunction(element, index, array) { // check that element is a string const isNotString = typeof element !== "string"; // if it's not, end function if (isNotString) { return; } // check that string is 3 characters long and only uppercase letters const isItThreeUpperCaseLetters = /^[A-Z]{3}$/.test(element); // otherwise, end function if (!isItThreeUpperCaseLetters) { return; } // check if all characters are different const allDifferentCharacters = element[0] !== element[1] && element[0] !== element[2] && element[1] !== element[2]; // if not, return to stop the function if (!allDifferentCharacters) { return; } // check if it's the first appearence of element inside the array const isItFirstAppearence = array.indexOf(element) === index; // if not, return to stop the function if (!isItFirstAppearence) { return; } return true; }
در کد بالا، برای بررسی سه مورد مختلف از یک عبارت منظم استفاده کردیم:/^[A-Z]{3}$/
.
اما اگر نمیخواهیم با عبارت منظم کار کنیم میتوانیم از ویژگی length
برای بررسی اینکه آیا یک رشته دقیقاً دارای طول مشخصی است یا نه استفاده کنیم. در این مورد element.length === 3
بررسی میکند که اینکه آیا رشته مورد نظر ما دقیقا سه کاراکتر دارد یا خیر.
پس از آن باید بررسی کنیم که رشته فقط شامل حروف و آن هم حروف بزرگ باشد.
برای انجام این کار میتوانیم از charCodeAt
استفاده کنیم. این روش کد اسکی کاراکتر را برمیگرداند و با دانستن اینکه حروف بزرگ دارای کدهای اسکی از ۶۵ تا ۹۰ هستند، میتوانید بررسی کنیم که آیا در این رشته فقط حروف بزرگ وجود دارد یا خیر.
سه عدد برای بررسی وجود دارد: element.charCodeAt(0)
، element.charCodeAt(1)
و element.charCodeAt(2)
. همه آنها باید بین ۶۵ تا ۹۰ باشند. با این که اینجا فقط سه کاراکتر داریم اما میتوانیم از یک حلقه نیز استفاده کنیم.
بنابراین مثال ما به صورت زیر خواهد بود:
for (let i = 0; i++; i < element.length) { // find the ASCII code of the character const code = element.charCodeAt(i); // check if it's outside of the range if (code < 65 || code > 90) { // if it is, return to stop the function return; } }
اکنون آن را به تابع اضافه میکنیم:
function callbackFunction(element, index, array) { // check that element is a string const isNotString = typeof element !== "string"; // if it's not, end function if (isNotString) {return;} // check that element has length string const hasLengthThree = element.length === 3; // if it has a different length, end function if (!hasLengthThree) {return;} // loop over the characters for (let i = 0; i++; i < element.length) { // find the ASCII code of the character const code = element.charCodeAt(i); // check if it's outside of the range if (code < 65 || code > 90) { // if it's outside the range, return and stop the function return; } } }
تابع callback را نوشتهایم. در این بخش بررسی میکنیم که چگونه میتوانیم از آن استفاده کنیم.
anArray.every(callbackFunction);
همچنین میتوانیم از متد every
که در داخل callback وجود دارد استفاده کنیم، شاید callback به متد filter باشد.
همانطور که یک برنامه پیچیدهتر میشود، احتمالاً از توابع callback بیشتری نیز استفاده خواهد کرد.
توابع callback یکی از ویژگیهای ساده جاوااسکریپت است. این بدان معنی است که ما میتوانیم یک تابع کلی داشته باشیم که کاری را انجام میدهد(مانند متد every
که بررسی میکند آیا هر المنت در یک آرایه با شرایط خاصی مطابقت دارد یا خیر، filter
که المنتهایی را که با یک شرایط خاص مطابقت ندارند حذف میکند، replace
یک string method است که یک callback میگیرد تا نحوه جایگزینی بخشهایی از یک رشته را توضیح دهد و غیره) و یک تابع callback برای اضافه کردن مشخصات آن رفتار برای موقعیت خاص.
filter
در آن موقعیت، المنتهای مشخص شده توسط callback را حذف میکند.every
بررسی میکند که همه المنتهای در یک موقعیت، همانطور که توسط تابع callback مشخص شده است باشند.replace
قسمتهایی از رشته را در موقعیتی که در آن استفاده میشود، همانطور که توسط callback مشخص شده است جایگزین میکند.توابع Higher order سطحی از انتزاع را به کد اضافه میکنند. ما نمیدانیم و نیازی وجود ندارد که بدانیم چگونه متد every
هر المنت آرایه را بررسی کرده و تأیید میکند که همه آنها تستهای مشخص شده توسط callback را پشت سر گذاشتهاند. فقط باید بدانیم که این متد یک تابع callback را برای این کار میپذیرد.
توابع callback توابعی هستند که به عنوان آرگومانهای توابع دیگر ارسال میشوند. در این مقاله سعی کردیم تا یک نمونه از تابع callback در جاوااسکریپت را باهم بنویسیم و در نهایت با نحوه استفاده از آنها و مزایایی که دارند آشنا شویم.
دیدگاهها: