جاوا اسکریپت به زبان ساده - جلسه یازدهم - فانکشن (پیشرفته)
مباحث از جمله پاس دادن متغیر به فانکشنها و نوشتن callback در هر فانکشن از جمله مواردی هستند که در این جلسه به آنها خواهیم پرداخت. فرض کنید هر روز قرار است یک کار تکراری انجام دهید. مثلا هر روز صبح زود، چای، قهوه یا شیر میل کنید. اگر خوردن صبحانه یک فانکشن (یک عمل تکراری) باشد، آن وقت نوع نوشیدنی که صبح زود میل میکنید (مثل شیر، چایی و قهوه) متغیر این فانکشن تکراری و روزانه است؛ متغیری که ممکن است هر روز بسته به نیازتان یکی را انتخاب کنید و به نتیجهی متناسب با انتخاب متغیرتان برسید.
بعد از این مقدمه کوتاه، به سراغ یک فانکشن واقعی در جاوا اسکریپت خواهیم رفت. فرض کنید یک فانکشن نیاز دارید که اسم و فامیلی فرد را بگیرد و آنها را به هم بچسباند. برای اینکه با یک بار نوشتن کد بتوانیم به چنین قابلیتی دست پیدا کنیم، چه باید کرد؟ باید نام و نام خانوادگی را بهعنوان متغیرهای فانکشن در نظر بگیریم! مثالهای زیر را ببینید تا درک بهتری از این موضوع کسب کنید.
مثال اول: یک سری اسم شامل محمد، علی و محسن داریم. در طرف دیگر یک سری فامیلی دلخواه مثل فراهانی، صدیقی و پورقاسمی داریم. حالا یک فانکشن نیاز داریم که کارش وصل کردن اسم هر فرد به یک فامیلی باشد. برای اینکه تنها با یک بار نوشتن یک فانکشن بتوانید این کار را انجام دهید:
۱) ابتدا یک فانکشن با نام دلخواه تعریف میکنیم:
function showMyName() {
}
۲) تا به این جلسه ما در کنار نام فانکشن (در اینجا showMyName) یک پرانتز خالی قرار میدادیم! این بار قرار است این پرانتزها با متغیرهای فانکشن پر شوند. در این فانکشن، ما درون پرانتز فانکشن سه متغیر با نامهای name و family نوشتهایم. به (متغیرها) که در داخل پرانتز فانکشن نوشته میشوند، متغیرهای فانکشن یا آرگیومنتهای فانکشن گفته میشود.
function showMyName(name,family) {
}
۳) حالا در داخل بلاک فانکشن (در واقع از باز تا بسته شدن آکولاد، بلاک و منطق اصلی فانکشن است) کار اصلی فانکشن را مینویسیم. کار اصلی فانکشن ما این است که متغیر نام و فامیلی را بگیرد و به هم بچسباند و نتیجه را به ما برگرداند. پس این وظیفه اصلی را در بلاک فانکشن تعریف میکنیم:
function showMyName(name,family) {
return name+family
}
نکته: اگر جلسه پیش را به خاطر داشته باشید، درون هر فانکشن به دستوری دسترسی داریم که return نام دارد! دستور return در واقع کارش ارائهی خروجی مطلوب از فانکشن است. در اینجا هم بعد از جمع کردن نام و نام خانوادگی با کمک دستور return، آن را به سمت کاربر باز میگردانیم!
۴) حالا نوبت به استفاده از این فانکشن است! تا به اینجای کار با نحوه نوشتن یک فانکشن دارای متغیر آشنا شدهایم! ولی چگونه باید از آن استفاده کنیم! این مرحله نحوه استفاده از یک فانکشن دارای متغیر است. به دقت به مثال زیر نگاه کنید:
var myName = showMyName('mohammad Hossein' , 'malek')
alert(myName)
همانطور که در این مثال دیدید، ما ابتدا نام فانکشن را نوشتهایم. همانطور که در جلسه پیش گفته شد، نوشتن نام فانکشن به همراه یک پرانتز باز و بسته، به معنای اجرای فانکشن است. سپس متغیرهای اسم و فامیل را بهصورت استرینگ به فانکشن پاس دادهایم! اگر به تعریف فانکشن نگاه کنید، این فانکشن دو متغیر پاس دادهشده را میگیرد و با یکدیگر جمع و نتیجه را Return میکند! پس متغیر myName در این مثال در نهایت حاوی مقدار خروجی return شده از سوی فانکشن خواهد بود.
اگر هنوز در درک ماهیت فانکشنها و نحوه تعریف متغیر برای آنها مشکل دارید نگران نباشید! میخواهیم این موضوع را از جنبهای سادهتر نگاه کنیم. برای سادهتر شدن مبحث بیایید یک مثال عینی روزمره بزنیم. یک دستگاه آبمیوهگیری را در نظر بگیرید. همانطور که این دستگاه از بخشهای مختلفی تشکیل شده است که هر کدام یک کار انجام میدهد و بخشهای مختلف آن با هم در ارتباط هستند، یک پروژه جاوا اسکریپت نیز از یک سری فانکشن تشکیل شده است. این فانکشنها گاهی به هم مرتبط میشوند و گاهی ارتباطی با هم ندارند؛ ولی بهطور کلی هر کدام بخشی از کار برنامه را بر عهده میگیرد و وظیفهای که برای تعریف شده است، انجام میدهد.
شما میتوانید هر نوع میوهای را بهعنوان ورودی در یک دستگاه آبمیوهگیری بیندازید و در نهایت یک مایع بهعنوان نوشیدنی نهایی تحویل بگیرید. درست است که هر بار نوع ماده ورودی عوض میشود؛ ولی عملکرد و کاری که روی ماده انجام میشود همیشه یکی است. در واقع فانکشنها هم همینقدر سر راست هستند!
وقتی ما یک فانکشن مینویسیم، در واقع یک عملکرد یا کاری را که قرار است بارها و بارها تکرار شود، در قالب یک کد مشخص تعریف میکنیم. سپس هر زمان که نیاز داشتیم این کد را مجددا استفاده میکنیم. برای اینکه بتوانیم هر بار که قصد استفاده از این تکه کد داریم، محتوای جدیدی بدان وارد کنیم و خروجی درست بگیریم، باید متغیرهایی برای آن تعریف کنیم. با نوشتن نامهای دلخواه در حین ساخت یک فانکشن، این متغیرها ایجاد میشود و فانکشن شما به یک سری متغیر جدید بهعنوان پارامتر دسترسی پیدا میکند.
حالا شما این قابلیت را دارید که هر بار میخواهید این فانکشن را استفاده کنید، اطلاعات دلخواهتان را بهعنوان ورودی به این فانکشن پاس بدهید تا فانکشن شما متغیرهای پاس دادهشده را بهعنوان ورودی در محاسباتش استفاده کند. برای درک بهتر گفتههای بالا، مثال دیگری میزنیم.
فرض کنید میخواهیم یک ماشین حساب ساده بنویسیم! برای آنکه هر بار دو عدد را با هم جمع کنیم چه راه حلی پیشنهاد میکنید؟ حتما میگویید یک فانکشن مینویسیم که متغیر اول و دوم را بهعنوان پارامترهای فانکشن دریافت کند و حاصل نهایی را نمایش دهد! درست است. این مثال به شیوه زیر نوشته میشود:
function calculator(num1,num2){
return num1 + num2
}
حالا هر بار بخواهیم دو عدد را جمع کنیم، کافی است از این فانکشن استفاده کنیم و دو متغیر عددی دلخواه را بدان پاس دهیم تا حاصل جمع آنها را به ما نمایش دهد. بهطور مثال میخواهیم ۵ و ۶ را از طریق این فانکشن جمع کنیم:
var fivePlusSix = calculator(5,6)
تفاوت بین فانکشنهای بدون متغیر و با متغیر:
اگر جلسه قبل را دنبال کرده باشید، میدانید که لزومی ندارد که همیشه یک متغیر به فانکشن بدهید. در واقع هنگامی که یک فانکشن را صدا میزنیم، میتوانیم بدون پاس دادن متغیر و به همان ترتیب جلسه قبلی عمل میکنیم:
function myFunction(){
//تعریف فانکشن بدون متغیر
}
myfunction() // صدا زدن یک فانکشن بدون متغیر مانند مثالهای قبلی
در این حالت فانکشن ما دارای متغیر خاصی نیست. در مثال زیر myFunction قرار است تعدادی متغیر را با هم جمع کند و نتیجه را در قالب پنجره alert نمایش دهد:
function myFunction(arg1,arg2,arg3) {
//درون فانکشن ما به arg1,arg2,arg3 دسترسی داریم
alert(arg1+arg2+arg3)
}
نکته جالب اینجا است که در حین صدا کردن یک فانکشن میتوانید هر نوع متغیری که دوست دارید بدان پاس دهید! یعنی وقتی داریم myFunction را صدا میزنیم، مهم نیست بهجای arg1 یک عدد گذاشتهایم یا متن! هر چه گذاشته باشیم در درون فانکشن ما عملیات تعیینشده را انجام خواهد داد. برای مثال در زیر ما سه اسم پاس دادهایم:
myFunction("ali ","sina ","mohammad")
و در مثال بعدی به جای سه اسم، سه عدد را بهعنوان متغیرهای فانکشن، پاس دادهایم:
myFunction("۱ ","۲ "," ۳")
ولی همانطور که در اجرای این کد مشاهده خواهید کرد، در هر حالت و با وجود متغیرهای متفاوتی که به فانکشن پاس دادهایم، در خروجی نهایی ما تفاوتی حاصل نشد. در واقع در هر سه حالت، فانکشن myFunction متغیرهایی را که بدان پاس دادهایم، صرف نظر از نام و نوع داده از ما گرفت، درون خود با اسمهای arg1,arg2,arg3 جمع کرد و خروجی آن را در قالب پنجره الرت به نمایش گذاشت.
نکات تکمیلی:
نکته اول: هر فانکشن میتواند بهصورت نامحدود متغیر جدید در خود جای دهد و سپس این متغیرها را در درون خود استفاده کند.
نکته دوم: لزومی ندارد همیشه یک استرینگ یا عدد را بهعنوان متغیر به فانکشن پاس بدهیم! ما حتی میتوانیم دادههایی را که از پیش در برنامه تعریف شدهاند، بهعنوان متغیر به فانکشن پاس بدهیم! مثال زیر را ببینید تا منظورمان از نکته را بهتر درک کنید.
فرض کنید که سه متغیر با نامهای name1 و name2 و name3 داریم:
var name1,name2,name3
همینجا باید بگوییم که حین تعریف چند متغیر میتوانید به جای اینکه هر بار کلمه var را بنویسید، یک بار آن را بنویسید و بین متغیرهای مختلف «,» بگذارید. بدین ترتیب مثل این است که سه متغیر جداگانه تعریف کرده باشید.
به هر یک از این متغیرها نام دلخواهمان را نسبت میدهیم:
name1 = "ali";
name2 = "davood"
name3 = "mahnaz"
سپس یک فانکشن تعریف میکنیم. در این فانکشن میخواهیم روی مقادیر متغیرهایی که بالاتر تعریف کردهایم تغییر ایجاد کنیم:
function myFunction(params1,params2,params3){
alert(params1,params2,params3)
}
این بار به جای کلمه arg از کلمه params استفاده کردیم تا بگوییم میتوانید هر نامی که دلتان میخواهد بهعنوان نام متغیرهای فانکشن استفاده کنید. این موضوع اهمیتی ندارد و هر نامی قابل قبول است. بدین ترتیب همه مثالهای زیر درست هستند:
function myFunction(one,two,three) {
}
function MyFunction(isItOk,HelloDude,ByDude) {
}
در تمامی این حالتها فانکشن ما خودش یک سری متغیر به نامهایی که داخل پرانتز نوشتهایم میسازد و از این به بعد هر چیزی که در حین صدا شدن فانکشن بدان پاس داده میشود با این نامها میشناسد.
نکات مهم:
۱) در حین پاس دادن پارامترها به فانکشنها به شماره آنها دقت کنید. برای مثال ما در زیر فانکشنی داریم که تنها یک متغیر میپذیرد:
function myFunction(arg1){
alert(arg1)
}
ولی در حین صدا زدن این فانکشن دو متغیر بدان پاس میدهیم:
myFunction("number1","number2")
در این حالت تنها ما به number1 که اولین متغیر است و با نام arg1 درون فانکشن myFunction شناخته میشود دسترسی داریم و نمیتوانیم از number2 استفاده کنیم.
۲) فرض کنید فانکشنی دارید که سه پارامتر دریافت میکند:
function myFunction(arg1,arg2,arg3){
alert(arg1)
alert( arg2)
alert(arg3)
}
و در حین صدا زدن:
myFunction("paraph1","paraph2")
در حین صدا زدن ما تنها دو متغیر بدان پاس دادهایم! پس تکلیف پارامتر سوم چه میشود! پارامتر سوم، درون فانکشن undefined یا تعریفنشده خواهد بود و نمیتوانید از آن استفاده کنید؛ چون اصلا در حین صدا زدن فانکشن تعریف نشده است.
مزیت استفاده از پارامترها در فانکشنها چیست؟
مهمترین مزیت این است که میتوانید با یک بار نوشتن فانکشن، یک کار ساده را با متغیرهای جدید تکرار کنید. یعنی یک بار یک فانکشن تعریف میکنید و عملیات خود را روی دادههای مختلف انجام میدهید؛ بدون آنکه نیاز باشد هر بار این فانکشن را تکرار کنید.
کال بک در فانکشنها (callBack):
Callback در واقع یک فانکشن است که بعد از اتمام یک فانکشن بلافاصله اجرا میشود. هر فانکشن میتواند دارای یک یا چند CallBack باشد. کال بک یکی از قابلیتهای فانکشن محسوب میشود که بعد از اجرای آن فانکشن و تمام شدن تمامی موارد آن مورد استفاده قرار میگیرد. مثلا فرض کنید میخواهید بعد از اینکه فلان اتفاق در فانکشن افتاد و تمام شد، به کاربر پیغام بدهد که کار شما با موفقیت انجام شد و پیغام الرت را به وی نمایش بدهد. نمایش پیغام آلرت، کال بک فانکشن برای فانکشن اصلی شما است که بهمحض تمام شدن فانکشن اصلی اجرا میشود.
نکته مهم در کال بک این است که تنها زمانی اتفاق میافتد که کار فانکشن بهصورت کامل و با موفقیت به اتمام رسیده باشد.
برای تعریف کال بک آخرین گزینه آرگیومنتهای شما باید فانکشن کال بک باشد. بعد از تعریف کال بک، آن را با همان اسمی که در آرگیومنتها تعریف کردیم صدا میزنیم:
function doSomething(callback) {
// کارهایی که فانکشن اصلی قرار است انجام دهد
// بعد از اتمام فانکشن اصلی فانکشن کال بک صدا زده میشود
callback('stuff', 'goes', 'here');
}
برای درک بهتر مثال توضیحات زیر را ببینید:
در ابتدا ما یک فانکشن کال بک که دوست داریم بعد از فانکشن اصلی اجرا شود مینویسیم (دقت کنید فانکشن کال بک باید قبل از فانکشن اصلی نوشته شود؛ چون جاوا اسکریپت کدهای شما را از بالا به پایین میخواند و اگر در حین صدا زدن فانکشن اصلی، کال بک قبلا تعریف نشده باشد، با ارور تعریفنشده روبهرو خواهید شد).
نام فانکشن کال بک ما iAmTheCallBackFunction است. این فانکشن سه متغیر a, b, c را میگیرد و آنها را در کنار هم و با یک فاصله (اسپیس) الرت میکند.
function iAmTheCallBackFunction(a, b, c) {
// من کالبک فانکشن هستم
alert(a + " " + b + " " + c);
}
حالا ما فانکشن اصلی خود را مینویسیم. نام این فانکشن mainFunction است. این فانکشن یک آرگیومنت به نام callback دارد که در واقع همان کال بک فانکشنی است که ما میخواهیم.
function mainFunction(callback){
//بعد از اتمام کار فانکشن ما کال بک را صدا بزن
callback()
}
حالا در حین صدا کردن فانکشن mainFunction میتوانیم iAmTheCallBackFunction را که خودش یک فانکشن است بهعنوان متغیر به فانکشن mainFunction پاس دهیم. سپس آن را در فانکشن اصلی استفاده کنیم. مطابق زیر:
mainFunction(iAmTheCallBackFunction);
بدین ترتیب بعد از تمام شدن فانکشن اصلی فانکشن کال بک بلافاصله صدا خواهد شد. از کال بک در موارد بسیار زیادی استفاده میشود. در جلسات آینده زمانی که سراغ setTimeOut و setInterval برویم ماهیت اصلی استفاده از فانکشنها را خواهید آموخت.
مثال پایانی:
قبل از اتمام این جلسه، میخواهیم یک مثال ساده را بهصورت یک پروژه کوچک بیان کنیم تا بهتر با مفاهیم گفتهشده در مورد فانکشنها آشنا شوید. اگر خاطرتان باشد در جسات قبلی ما یک پروژه مدیریت رستوران آنلاین را آغاز کرده بودیم. حالا میخواهیم به کمک دانش فعلیمان آن را حرفهایتر از قبل بنویسیم.
توضیح پروژه: این پروژه قرار است به کاربر امکان بدهد تا یک سری غذا انتخاب کند و در صورتی که مشتری خرید بالاتر از ۱۰ هزار تومان داشت به وی تخفیف ۱۰ درصدی بدهد.
HTML
منوی غذاها
پیتزا پپرونی
onclick="addToBasket('add',5000)">اضافه به سبد
onclick="addToBasket('remove',5000)">حذف از سبد
پیتزا مخصوص
onclick="addToBasket('add',4000)">اضافه به سبد
onclick="addToBasket('remove',4000)">حذف از سبد
پیتزا ویژه سرآشپز
onclick="addToBasket('add',6000)">اضافه به سبد
onclick="addToBasket('remove',6000)">حذف از سبد
onclick="showFinalPrice()">نمایش قیمت کل
فایل جاوا اسکریپت
var totalPrice = 0;
var finalPrice = 0; //بعد از محاسبه تخفیف - درصورت دریافت تخفیف
var addToBasket = function(addOrRemove,price) {
if( addOrRemove == 'add' ) {
totalPrice += price;
alert("تومان به سبد خرید شما اضافه شد " + price )
}
else if ( addOrRemove == 'remove' ){
totalPrice -= price;
alert("از سبد خرید شما حذف شد" + price)
}
}
var secialOffer = function() {
offerPercentage = totalPrice * (10/100);
finalPrice = totalPrice - offerPercentage;
alert(finalPrice)
}
var showFinalPrice = function() {
if ( totalPrice > 10000 ) {
secialOffer()
}
else {
alert(totalPrice)
}
}
اگر یکبار این کد را خودتان مطالعه کردهاید، میخواهیم یک توضیح کوتاه در مورد آن بدهیم. اول از همه از markUp اچتیامال شروع میکنیم. در اینجا لیست غذاها را گذاشتهایم و در جلوی هر کدام از آنها یک دکمه «اضافه» و یک دکمه «حذف» قرار دارد. اکشن جاوا اسکریپتی که روی دکمهها گذاشتهایم یک فانکشن به نام addToBasket است که تنها پارامترهای آن هر بار تغییر میکند! اینجا کاربرد استفاده از متغیر در فانکشنها مشخص میشود. بهجای نوشتن ۱۰ باره یک فانکشن، سبد خرید را یک بار نوشته و متغیرهای مختلف را در آن استفاده کردهایم.
در فایل جاوا اسکریپت یک سری فانکشن و متغیر داریم. متغیرهای ما همانهایی هستند که در حین کد قصد تغییر و استفاده مجدد از آنها را داریم. برای همین یک بار آنها را بهعنوان متغیرهای گلوبال یا عمومی در بالای کد تعریف کردهایم تا هر وقت خواستیم به آنها دسترسی داشته باشیم.
کلیت منطق برنامه اینگونه است که با هر بار کلیک روی دکمه حذف یا اضافه به سبد خرید، فانکشن addToBasket اجرا میشود. این فانکشن دارای دو متغیر است. متغیر اول که در فانکشن با نام addOrRemove ایجاد شده است، چک میکند که کاربر قصد اضافه کردن به سبد خریدش دارد یا حذف محصول از آن! این چک کردن نیز بهسادگی انجام میشود. روی دکمه اضافه به سبد خرید استرینگ "add" را در داخل پرانتز فانکشن نوشتهایم و بدین ترتیب این استرینگ را بهعنوان متغیر به فانکشن پاس دادهایم و در حالت حذف استرینگ remove را نوشتهایم.
این فانکشن در نهایت چک میکند که پارامتری که به ما پاس داده شده است چیست. اگر پارامتر ابتدایی یا همان addOrRemove دارای مقدار add بود، میفهیم که یوزر روی دکمه اضافه به سبد خرید کلیک کرده است. پس قیمت نهایی سفارش وی را با قیمت محصول جمع میکنیم و اگر حذف بود، قیمت محصول را از سبد خرید وی کسر میکنیم.
فانکشن بعدی ما specialOffer است! گفتیم این فانکشن قرار است در صورتی که خرید کاربر بالای ۱۰ هزار تومان بود تخفیف لازم را روی قیمت سبد خرید وی لحاظ کند! به همین خاطر در این فانکشن ما ابتدا یک متغیر offerPercentage ساختهایم که در واقع قرار است مقدار تخفیف را به تومان برای ما محاسبه کند. (میزان تخفیف میشود قیمت کل ضرب در ۱۰ درصد)!
در نهایت نیز قیمت نهایی را از مقدار بهدستآمده از offerPercentage کم کردهایم تا قیمت بعد از تخفیف سبد خرید محاسبه شود!
آخرین فانکشن ما showFinalPrice است که بعد از کلیک روی دکمه نمایش سبد خرید در انتهای اچتیامال صدا زده میشود. این فانکشن ابتدا چک میکند که اگر قیمت خرید کاربر بیشتر از ۱۰ هزار تومان است برای وی تخفیف لحاظ کند و سپس قیمت نهایی را در قالب پنجره alert به ما نمایش میدهد.
سخن پایانی:
امیدواریم در این جلسه با مفهوم فانکشن و پاس دادن متغیر به فانکشنها که یکی از مهمترین نکات پایهای در جاوا اسکریپت است آشنا شده باشید. در جلسه آینده سراغ object خواهیم رفت و موضوعات مرتبط با دادهها را عمیقتر از پیش مورد بررسی قرار خواهیم داد.
نظرات