نحوه استفاده از Callback و توابع سفارش بالاتر در جاوا اسکریپت
نحوه برخورد و استفاده از توابع در جاوا اسکریپت بسیار جالب است. آنها بسیار انعطاف پذیر هستند - ما می توانیم یک تابع را به عنوان یک مقدار به یک متغیر اختصاص دهیم، آنها را به عنوان یک مقدار از یک تابع دیگر برگردانیم، و آنها را به عنوان یک آرگومان به یک تابع دیگر منتقل کنیم. ما می توانیم همه این کارها را انجام دهیم زیرا جاوا اسکریپت با توابع به عنوان شهروندان درجه یک رفتار می کند.
در این مقاله، به این می پردازم که توابع و فراخوان های مرتبه بالاتر چیست و چگونه در جاوا اسکریپت کار می کنند.
به عنوان شهروندان درجه یک در جاوا اسکریپت عمل می کند
توابع به عنوان شهروندان درجه یک یا اشیاء درجه یک در جاوا اسکریپت تعریف می شوند زیرا توابع مانند متغیرها رفتار می شوند.
این بدان معنی است که توابع در جاوا اسکریپت می توانند:
به عنوان یک آرگومان به یک تابع دیگر منتقل می شود.
به عنوان یک مقدار به یک متغیر اختصاص داده شده است.
به عنوان یک مقدار از یک تابع برگردانده می شود.
درک نحوه برخورد با توابع در جاوا اسکریپت ضروری است، زیرا آنها به عنوان یک بلوک سازنده برای درک توابع مرتبه بالاتر و پاسخ به تماس در جاوا اسکریپت و نحوه کار آنها عمل می کنند.
توابع مرتبه بالاتر چیست؟
توابع مرتبه بالاتر توابعی هستند که توابع را به عنوان آرگومان می گیرند و همچنین یک تابع را به عنوان مقدار برمی گردانند.
تعداد زیادی توابع مرتبه بالاتر داخلی در جاوا اسکریپت وجود دارد. ما به برخی از آنها نگاهی خواهیم انداخت و از نحوه برخورد با عملکردها به عنوان شهروندان درجه یک استفاده خواهیم کرد. ما همچنین توابع مرتبه بالاتر خود را ایجاد خواهیم کرد.
ابتدا، اجازه دهید به چند نمونه از توابع مرتبه بالاتر داخلی نگاهی بیندازیم.
روش های آرایه
متدهای آرایه معمولاً اولین معرفی توابع درجه بالاتری هستند که یک توسعه دهنده در هنگام یادگیری جاوا اسکریپت خواهد داشت. اینها شامل، اما نه محدود به، map
، filter
، forEach
، find
، findIndex
، some
و every
آرایه ای که توسط جاوا اسکریپت ارائه شده است.
این روش ها یا توابع آرایه مشترکات زیادی دارند، اما یکی از رایج ترین ویژگی ها این است که همه آنها یک تابع را به عنوان یک آرگومان می پذیرند. در زیر یک قطعه کد وجود دارد که نحوه عملکرد متد forEach
آرایه را نشان می دهد:
const people = [ { firstName: "Jack", year: 1988 }, { name: "Kait", year: 1986 }, { name: "Irv", year: 1970 }, { name: "Lux", year: 2015 }, ]; people.forEach(function (person) { console.log(person); }); // Output: Logs every person object in the array
از نمونه کد بالا، می بینیم که متد forEach
تابعی را به عنوان آرگومان می پذیرد که هر تکرار روی آرایه را فراخوانی می کند. پس متد forEach
آرایه یک تابع مرتبه بالاتر است.
رویدادهای تایمر
مجموعه دیگری از توابع داخلی که معمولاً مورد استفاده قرار می گیرند توابع setInterval
و setTimeout
هستند که به عنوان رویدادهای تایمر در جاوا اسکریپت شناخته می شوند.
هر تابع یک تابع را به عنوان یکی از آرگومان های خود می پذیرد و از آن برای ایجاد یک رویداد زمان بندی شده استفاده می کند.
به نمونه کد زیر نگاه کنید تا ببینید setTimeout
چگونه کار می کند:
setTimeout(function () { console.log("This is a higher order function"); }, 1000); // Output: "This is a higher order function" after 1000ms / 1 second
قطعه کد بالا ابتدایی ترین مثال از نحوه عملکرد یک تابع setTimeout
است. تابع و مدت زمان را بر حسب میلی ثانیه می پذیرد و پس از گذشت مدت زمان ارائه شده، تابع را اجرا می کند.
از مثال بالا، This is a higher order function
پس از 1000 میلی ثانیه یا یک ثانیه در کنسول چاپ می شود.
setInterval(function () { console.log("This is a higher order function"); }, 1000); // Output: "This is a higher order function" after every 1000ms / 1 second
تابع setInterval
مشابه تابع setTimeout
است، درست مانند روشهای آرایه - اگرچه عملکرد متفاوتی دارد. اما میتوانیم یک الگوی مشترک ببینیم: تابعی را نیز به عنوان یکی از پارامترهای خود میپذیرد.
برخلاف setTimeout
(که تابع را پس از سپری شدن مدت زمان ارائه شده اجرا می کند)، setInterval
این تابع را بارها و بارها هر 1000 میلی ثانیه یا 1 ثانیه اجرا می کند.
نحوه ایجاد و استفاده از تابع سفارش بالاتر
توابع سفارش بالاتر به توابع داخلی ارائه شده توسط جاوا اسکریپت محدود نمی شوند.
از آنجایی که توابع در جاوا اسکریپت به عنوان اشیاء درجه یک در نظر گرفته می شوند، می توانیم از این رفتار استفاده کنیم و توابع بسیار کارآمد و قابل استفاده مجدد بسازیم.
در مثالهای زیر، چند تابع میسازیم. آنها نام مشتری و یک تبریک را می پذیرند و سپس آن اطلاعات را در کنسول چاپ می کنند.
اول، در اینجا یک تابع ساده است که هر دوی این کارها را انجام می دهد:
function greetCustomer(firstName, lastName, salutation) { const fullName = `${firstName} ${lastName}`; console.log(`${salutation} ${fullName}`); } greetCustomer("Franklin", "Okolie", "Good Day"); // Output: "Good Day Franklin Okolie"
greetCustomer
3 آرگومان را می پذیرد: نام، نام خانوادگی و سلام. سپس یک تبریک به مشتری را به کنسول چاپ می کند.
اما این عملکرد یک مشکل دارد - این کار دو کار را انجام می دهد: نوشتن نام کامل مشتری و همچنین چاپ تبریک.
این بهترین روش نیست، زیرا توابع باید فقط یک کار را انجام دهند و آن را به خوبی انجام دهند. پس ما میخواهیم کد خود را دوباره اصلاح کنیم.
تابع دیگری باید نام مشتری را بنویسد تا تابع greetCustomer
فقط پیام تبریک را به کنسول چاپ کند. پس بیایید تابعی بنویسیم که آن را مدیریت کند:
function composeName(firstName, lastName) { const fullName = `${firstName} ${lastName}`; return fullName; }
اکنون که تابعی داریم که نام و نام خانوادگی مشتری را ترکیب می کند، می توانیم از آن تابع در greetCustomer
استفاده کنیم:
function greetCustomer(composerFunc, firstName, lastName, salutation) { const fullName = composerFunc(firstName, lastName); console.log(`${salutation} ${fullName}`); } greetCustomer(composeName, "Franklin", "Okolie", "Good Day"); // Output: "Good Day Franklin Okolie"
اکنون این تمیزتر به نظر می رسد و هر عملکرد فقط یک کار را انجام می دهد. تابع greetCustomer
اکنون 4 آرگومان را می پذیرد، و از آنجایی که یکی از آن آرگومان ها یک تابع است، اکنون یک تابع مرتبه بالاتر است.
شاید قبلاً از خود پرسیده باشید که چگونه یک تابع در یک تابع دیگر فراخوانی می شود و چرا؟
اکنون به تحلیل فراخوانی تابع می پردازیم و به هر دوی این سؤالات پاسخ می دهیم.
برگرداندن یک تابع به عنوان یک مقدار
به یاد داشته باشید که توابع مرتبه بالاتر یا یک تابع را به عنوان پارامتر می گیرند و/یا یک تابع را به عنوان مقدار برمی گردانند.
بیایید تابع greetCustomer
را مجدداً تغییر دهیم تا از آرگومان های کمتری استفاده کنیم و یک تابع برگردانیم:
function getGreetingsDetails(composerFunc, salutation) { return function greetCustomer(firstName, lastName) { const fullName = composerFunc(firstName, lastName); console.log(`${salutation} ${fullName}`); };
آخرین نسخه greetCustomer
استدلال های زیادی را پذیرفت. چهار آرگومان زیاد نیست، اما اگر ترتیب استدلال ها را به هم بزنید باز هم خسته کننده خواهد بود. به طور کلی، هر چه کمتر استدلال داشته باشید، بهتر است.
پس در مثال بالا، تابعی به نام getGreetingDetails
داریم که composerFunc
و salutation
از طرف تابع greetCustomer
داخلی می پذیرد. سپس تابع greetCustomer
داخلی را برمی گرداند، که خود firstName
و lastName
به عنوان آرگومان می پذیرد.
با انجام این کار، greetCustomer
به طور کلی آرگومان های کمتری دارد.
و با آن، بیایید نگاهی به نحوه استفاده از تابع getGreetingDetails
بیندازیم:
const greet = getGreetingsDetails(composeName, "Happy New Year!"); greet("Quincy", "Larson"); // Output: "Happy New Year Quincy Larson"
حالا یک قدم به عقب بردارید و این انتزاع زیبا را تحسین کنید. شگفت انگیز! ما از جادوی توابع مرتبه بالاتر برای ساده سازی تابع greetCustomer
استفاده کرده ایم.
بیایید نحوه عملکرد همه چیز را مرور کنیم. تابع مرتبه بالاتر به نام getGreetingDetails
دارای دو آرگومان است: یک تابع برای نوشتن نام و نام خانوادگی مشتری و یک سلام. سپس تابعی به نام greetCustomer
برمی گرداند که نام و نام خانوادگی مشتری را به عنوان آرگومان می پذیرد.
تابع greetCustomer
برگردانده شده نیز از آرگومان پذیرفته شده توسط getGreetingDetails
برای اجرای برخی اقدامات نیز استفاده می کند.
در این مرحله احتمالاً از خود می پرسید که چگونه یک تابع برگشتی می تواند از آرگومان های ارائه شده به یک تابع والد استفاده کند؟ به خصوص با توجه به نحوه عملکرد زمینه اجرای تابع. به دلیل بسته شدن امکان پذیر است. بیایید اکنون در مورد آنها بیشتر بدانیم.
بسته ها توضیح داده شده است
بسته شدن تابعی است که به متغیر موجود در محدوده ای که در آن ایجاد شده است دسترسی دارد حتی پس از اینکه دامنه دیگر در زمینه اجرا وجود نداشته باشد. این یکی از مکانیسمهای زیربنایی تماسهای بک است، زیرا بازخوانیها همچنان میتوانند به متغیرهای ایجاد شده در یک تابع بیرونی پس از بسته شدن آن تابع بیرونی ارجاع داده و از آن استفاده کنند.
بیایید یک مثال سریع بزنیم:
function getTwoNumbers(num1, num2) { return function add() { const total = num1 + num2; console.log(total); }; } const addNumbers = getTwoNumbers(5, 2); addNumbers(); //Output: 7;
کد موجود در این مثال تابعی به نام getTwoNumbers
را تعریف می کند و به شما نشان می دهد که چگونه بسته شدن ها کار می کنند. بیایید آن را با جزئیات بیشتر تحلیل کنیم:
getTwoNumbers
به عنوان تابعی تعریف می شود که دو پارامتر num1
و num2
را می گیرد.
در داخل getTwoNumbers
، تابع دیگری را برمی گرداند که یک تابع درونی به نام add
است.
تابع add
، هنگام فراخوانی، مجموع num1
و num2
را محاسبه می کند و نتیجه را در کنسول ثبت می کند.
خارج از تابع getTwoNumbers
، متغیری به نام addNumbers
ایجاد می کنیم و نتیجه فراخوانی getTwoNumbers(5, 2)
را به آن اختصاص می دهیم. این به طور موثر بسته ای را ایجاد می کند که در آن addNumbers
اکنون مقادیر 5
و 2
را به عنوان num1
و num2
"به یاد می آورد".
در نهایت برای اجرای تابع add
داخلی addNumbers()
فراخوانی می کنیم. از آنجایی که addNumbers
یک بسته است، همچنان به مقادیر num1
و num2
دسترسی دارد که به ترتیب روی 5
و 2
تنظیم شده بودند. مجموع آنها را محاسبه می کند و 7
در کنسول ثبت می کند.
اگر می خواهید در مورد بسته شدن بیشتر بدانید، اینجا بیشتر بخوانید .
بازگشت به تابع مرتبه بالاتر ما. تابع برگشتی greetCustomer
به عنوان مقداری برمی گردد که در متغیری به نام greet
ذخیره می کنیم.
انجام این کار باعث می شود که متغیر greet
خود یک تابع باشد، به این معنی که می توانیم آن را به عنوان یک تابع فراخوانی کنیم و آرگومان هایی را برای نام و نام خانوادگی ارسال کنیم.
و violà وجود دارد که شما آن را دارید. درک این مفاهیم در ابتدا ممکن است کمی پیچیده باشد، اما زمانی که آنها را درک کنید، هرگز شما را رها نمی کنند.
من شما را تشویق میکنم که دوباره بخشهای قبلی را بخوانید، با کدهای ویرایشگر خود بازی کنید و از نحوه کار همه چیز با هم مطلع شوید.
اکنون که درک عمیقی در مورد نحوه عملکرد توابع مرتبه بالاتر دارید، بیایید در مورد توابع برگشت به تماس صحبت کنیم.
توابع برگشت به تماس چیست؟
تابع فراخوانی تابعی است که به عنوان آرگومان به تابع دیگری ارسال می شود.
باز هم، یکی از عوامل تعیین کننده توابع به عنوان شهروندان درجه یک، توانایی آن برای انتقال به عنوان آرگومان به تابع دیگری است. به این عمل انتقال تماس ها می گویند.
اجازه دهید به عقب برگردیم و به رویدادهای زمانی که قبلاً در مورد توابع داخلی ارائه شده در جاوا اسکریپت یاد میگرفتیم، بحث کردیم. در اینجا دوباره تابع setTimeout
است:
setTimeout(function () { console.log("This is a higher order function"); }, 1000); // Output: "This is a higher order function" after 1000ms / 1 seconds
ما ثابت کردهایم که تابع setTimeout
یک تابع مرتبه بالاتر است زیرا تابع دیگری را به عنوان آرگومان میپذیرد.
تابعی که به عنوان آرگومان به تابع setTimeout
ارسال می شود، تابع callback نامیده می شود. این به این دلیل است که در داخل تابع مرتبه بالاتری که به آن منتقل شده است فراخوانی یا اجرا می شود.
برای درک بهتر توابع پاسخ به تماس، اجازه دهید نگاهی دیگر به تابع greetCustomer
از قبل بیندازیم:
// THIS IS A CALLBACK FUNCTION // IT IS PASSED AS AN ARGUMENT TO A FUNCTION function composeName(firstName, lastName) { const fullName = `${firstName} ${lastName}`; return fullName; } // THIS IS A HIGHER ORDER FUNCTION // IT ACCPEPTS A FUNCTION AS A ARGUMENT function greetCustomer(composerFunc, firstName, lastName, salutation) { const fullName = composerFunc(firstName, lastName); console.log(`${salutation} ${fullName}`); } greetCustomer(composeName, "Franklin", "Okolie", "Good Day"); // Output: "Good Day Franklin Okolie"
composeName
یک تابع callback است که به عنوان آرگومان به تابع greetCustomer
یک تابع مرتبه بالاتر ارسال می شود و در داخل این تابع اجرا می شود.
تفاوت بین توابع مرتبه بالاتر و توابع برگشت به تماس
مهم است که تفاوت بین این دو عبارت را درک کنیم تا بتوانیم با هم تیمی ها و در طول مصاحبه های فنی واضح تر ارتباط برقرار کنیم:
تابع مرتبه بالاتر : تابعی که تابعی را به عنوان آرگومان می پذیرد و/یا تابعی را به عنوان مقدار آن برمی گرداند.
تابع Callback : تابعی که به عنوان آرگومان به تابع دیگری ارسال می شود.
یک کیف و کتاب
برای درک بیشتر این اصطلاحات، من یک تشبیه ساده را به اشتراک می گذارم.
تصور کنید یک کیف و یک کتاب دارید. هنگام شرکت در جلسه، کلاس رفتن، رفتن به کلیسا و غیره کتاب را در کیف خود حمل می کنید.
در این سناریو، کیف کتاب شما را برای حمل آن میپذیرد و زمانی که میخواهید از آن استفاده کنید، آن را برمیگرداند. پس کیف مانند یک تابع مرتبه بالاتر است.
این کتاب تا زمانی که برای استفاده آماده شود در داخل کیف نگهداری می شود، پس مانند یک عملکرد برگشت به تماس است.
سوخت و مخزن سوخت
بیایید نگاهی به قیاس دیگری بیندازیم. سوخت و مخزن سوخت
برای سوخت رسانی به خودرو، باید سوخت را از طریق مخزن سوخت بریزیم، مخزن سوخت سوخت را دریافت می کند - درست مانند یک عملکرد مرتبه بالاتر.
سوخت در مخزن سوخت ریخته می شود - مانند یک عملکرد برگشتی.
امیدوارم این تشابه ها به ساده سازی بیشتر توابع ترتیب بالاتر و پاسخ به تماس و تفاوت بین آنها کمک کند.
نتیجه
همانطور که می بینید، توابع در جاوا اسکریپت بسیار انعطاف پذیر هستند و می توانند به روش های مفید زیادی استفاده شوند. این انعطافپذیری همچنین منجر به دو اصطلاح فنی رایج در جاوا اسکریپت میشود، توابع مرتبه بالاتر و توابع برگشت تماس.
اگر میخواهید درباره این موضوعات بیشتر بیاموزید، مستندات MDN را در مورد عملکردهای شهروندان درجه یک ، عملکردهای مرتبه بالاتر و توابع پاسخ به تماس تحلیل کنید.
امیدوارم از این مقاله چیزهای زیادی یاد گرفته باشید و امیدوارم از دانش جدید خود برای بیان واضح تر افکار خود در جلسات کدنویسی زوجی یا در طول مصاحبه های فنی استفاده کنید.
برای نکات بیشتر در مورد جاوا اسکریپت، من را در توییتر دنبال کنید.
با تشکر برای خواندن! بعدا می بینمت.
ارسال نظر