تابع جاوااسکریپت Function

آخرین به روزرسانی در 31 خرداد 1402
نوشته شده توسط علی خادم
تابع جاوااسکریپت

تابع جاوااسکریپت چیه؟

می‌خوام با ساده‌ترین تعریفی که می‌تونم از تابع جاوااسکریپت ارائه بدم شروع کنم: یه تابع، مجموعه‌ای از کُدهاس که یک یا چند عملیات به‌خصوص انجام می‌ده. اصلاً نگران نباشید، قراره همه چی براتون کاملاً روشن بشه و بعد که یاد گرفتین چطوری از تابع‌ها استفاده کنید، قراره کلی کارهای باحال انجام بدید!

تابع‌ها اساسی‌ترین عناصر همه برنامه‌های p5.js هستن. وقتی یه تابع ساخته می‌شه، دیگه لازم نیست کدی که داخل اون تابع نوشته شده دوباره جای دیگه‌ای تکرار بشه، بلکه کافیه از همون تابع استفاده بشه. تا حالا توی خیلی از مثال‌ها از تابع‌های آماده‌ای مثل createCanvas و fill استفاده کردیم. علاوه بر تابع‌های آماده‌ای که p5.js در اختیارمون قرار می‌ده، خودمون هم می‌تونیم تابع بنویسیم و توی برنامه‌مون ازش استفاده کنیم.

قبل از هر چیز می‌خوام از تابع‌های آماده‌ی p5.js استفاده کنم و یه جغد بکشم:

function setup() {
     createCanvas(windowWidth, windowHeight)
}
function draw() {
     background(204)
     translate(110, 175)
     stroke(0)
     strokeWeight(70)
     line(0, -35, 0, -65)
     noStroke()
     fill(255, 255, 255)
     ellipse(-17.5, -65, 35, 35)
     ellipse(+17.5, -65, 35, 35)
     arc(0, -65, 70, 70, 0, PI)
     fill(0)
     ellipse(-14, -65, 8, 8)
     ellipse(+14, -65, 8, 8)
     quad(0, -58, 4, -51, 0, -44, -4, -51)
}
یک جغد که با تابع های آماده در p5.js کشیده شده است.

فعلاً خیلی با جزییات این کد کاری نداشته باشید و فقط این کد رو کپی کنید و نتیجه رو ببینید. دقت کنید که من از translate استفاده کردم؛ این تابع نقطه صفر و صفر بوم شما رو از بالا سمت چپ جابجا می‌کنه و به نقطه جدیدی که شما تعیین می‌کنید تغییر می‌ده؛ از این جا به بعد، همه مختصاتی که وارد می‌کنید نسبت به این نقطه صفر و صفرِ جدید تعیین می‌شه.

کدی که الان نوشتیم تا این جغد به وجود بیاد هیچ مشکلی نداره و خیلی هم منطقی به نظر می‌رسه؛ اما اگه قرار باشه به جای این یه دونه جغد، دو تا جغد خوشگل داشته باشیم، اون وقت اندازه کُدمون دو برابر می‌شه؛ ببینید:

function setup() {
     createCanvas(windowWidth, windowHeight)
}
function draw() {
     background(204)

     // owl one
     translate(110, 175)
     stroke(0)
     strokeWeight(70)
     line(0, -35, 0, -65)
     noStroke()
     fill(255, 255, 255)
     ellipse(-17.5, -65, 35, 35)
     ellipse(+17.5, -65, 35, 35)
     arc(0, -65, 70, 70, 0, PI)
     fill(0)
     ellipse(-14, -65, 8, 8)
     ellipse(+14, -65, 8, 8)
     quad(0, -58, 4, -51, 0, -44, -4, -51)

     // owl two
     translate(70, 0)
     stroke(0)
     strokeWeight(70)
     line(0, -35, 0, -65)
     noStroke()
     fill(255, 255, 255)
     ellipse(-17.5, -65, 35, 35)
     ellipse(+17.5, -65, 35, 35)
     arc(0, -65, 70, 70, 0, PI)
     fill(0)
     ellipse(-14, -65, 8, 8)
     ellipse(+14, -65, 8, 8)
     quad(0, -58, 4, -51, 0, -44, -4, -51)

}
دو جغد که با تابع های آماده در p5.js کشده شده اند.

به غیر از background که مربوط به رنگ پس‌زمینه بود، من همه خطوط رو کپی کردم و برای جغد جدید translate رو تغییر دادم تا کنار جغد قبلی قرار بگیره؛ درسته که داره کار می‌کنه، ولی این کد منطقی و بهینه نیست؛ چون تعداد زیادی خط تکراری توی کد وجود داره و این اصلاً جذاب نیست. از طرفی، فرض کنید به جای دو تا جغد قرار بود مثلاً پونزده تا جغد داشته باشیم؛ این جور مواقع باید چی کار کنیم؟

باید یه تابع بنویسیم!

توی مثال بعد یه تابع می‌نویسیم که برامون جغد بکشه. این طوری لازم نیست هر بار که به یه جغد نیاز داشتیم این همه خط کد بنویسیم یا کپی‌پیست کنیم:

function setup() {
     createCanvas(windowWidth, windowHeight)
}
function draw() {
     background(204)
     owl(110, 175)
     owl(70, 0)
     owl(70, 0)
}
function owl(x, y) {
     translate(x, y)
     stroke(0)
     strokeWeight(70)
     line(0, -35, 0, -65)
     noStroke()
     fill(255, 255, 255)
     ellipse(-17.5, -65, 35, 35)
     ellipse(+17.5, -65, 35, 35)
     arc(0, -65, 70, 70, 0, PI)
     fill(0)
     ellipse(-14, -65, 8, 8)
     ellipse(+14, -65, 8, 8)
     quad(0, -58, 4, -51, 0, -44, -4, -51)
}
این بار برای ساختن جغدها از یک تابع جاوااسکریپت استفاده کردیم.

با کلیدواژه function یه تابع ساختم و اسمش رو owl گذاشتم؛ توی پرانتزی که جلوش باز و بسته شده، دو تا پارامتر براش در نظر گرفتم که بتونم با هر بار فراخوندن تابع owl مختصات جغد جدیدو تغییر بدم، تا جایی که دوست دارم قرار بگیره. پارامترها بخش خیلی مهمی از تابع‌ها هستن، چون باعث می‌شه بتونیم از یه تابع ثابت، خروجی‌های متغیر بگیریم؛ مثلاً اگه می‌خواستیم می‌تونستیم رنگ و ابعاد جغدها رو هم با همین یک تابع تغییر بدیم؛ بعد از این که تابع رو درست کردم، اون رو سه بار توی تابع draw فراخوندم. می‌بینید؟ با این که این بار سه تا جغد داریم، اما کدمون کوتاه‌تر و تمیزتر از کد قبلی شده؛ این طوری بهتر نیست؟

پس برای ساختن یه تابع باید این کارها رو انجام بدیم:

  • از کلیدواژه function استفاده می‌کنیم
  • اسم تابع رو انتخاب می‌کنیم و می‌نویسیم
  • توی پرانتز جلوش، پارامترها رو می‌نویسیم (اگه تابع پارامتری نداشت، پرانتزها خالی می‌مونن)
  • توی براکت جلوش، کدی که قراره با فراخونده شدن تابع اجرا بشه رو می‌نویسیم
  • هر جایی که خواستیم، با استفاده از اسمِ تابع، تابع رو فراخونی می‌کنیم و پارامترهاشو می‌نویسیم

برگردوندن «مقدار»

یه کاری که تابع‌ها می‌تونن انجام بدن و برنامه‌نویس‌ها زیاد ازش استفاده می‌کنن اینه که یه محاسباتی رو انجام بدن و در نهایت یه «مقدار»ی رو برگردونن. مثلاً p5.js یه تابع آماده‌ای داره به نام random که وقتی فراخونی می‌شه به صورت تصادفی یه عدد به ما برمی‌گردونه و ما می‌تونیم این عدد تصادفی رو داخل یه متغیر ذخیره کنیم (اگه نمی‌دونید متغیر چیه باید یه نگاهی به مطلب قبلی که درباره متغیرها نوشتم بندازید):

const randomNumber = random(1, 10)

اگه مثل من به تولید تصاویر جِنِریتیو علاقه‌مند باشید باید بدونید که قراره خیلی از این تابع random استفاده کنید، چون اساساً هنر مولد و تصاویر جِنِریتیو معمولاً بر اساس مقادیر تصادفی به وجود میان. به شکل‌های مختلف می‌شه از تابع random استفاده کرد؛ مثلا:

  • اگه هیچ عددی به عنوان پارامتر بهش ندید: یه عدد تصادفی بین صفر و یک برمی‌گردونه
  • اگه یک عدد به عنوان پارامتر بهش بدید: یه عدد تصادفی بین صفر و اون عدد برمی‌گردونه
  • اگه دو تا عدد به عنوان پارامتر بهش بدید: یه عدد تصادفی بین اون دو عدد برمی‌گردونه

البته اینایی که گفتم همه قابلیت‌های این تابعِ شگفت‌انگیز نیست؛ حتماً صفحه مربوط به تابع random توی رفرنس p5.js رو بخونید تا اطلاعات کاملی به دست بیارید.

چطوری خودمون یه تابع بسازیم که «مقدار» برگردونه؟

برای این کار باید پارامترهایی که نیاز داریمو مشخص کنیم، کدی که قراره محاسبه رو انجام بده بنویسیم و در نهایت از کلیدواژه return استفاده کنیم تا مقدار مد نظرمون رو به دست بیاریم:

function setup() {
  
     console.log(sum(3, 4, 5))
     // 12
  
}
function draw() {

}
function sum(a, b, c) {
     return a + b + c
}

یه تابع اگه فراخونده نشه اثری روی برنامه نداره؛ در واقع تابع‌ها بعد از تعریف شدن حتماً باید یه جایی استفاده بشن، وگرنه تعریف شدنشون بی‌فایده بوده. ممکنه براتون عجیب باشه که چرا تابع‌های setup و draw که توی برنامه‌های p5.js وجود دارن، بدون فراخونده شدن اجرا می‌شن؟ این به خاطر معماری این کتابخونه‌س؛ به دلایلی سازنده‌های p5.js تصمیم گرفتن که این طوری کار کنه و توی رفرنس رسمی p5.js هم نوشته شده که تابع‌های setup و draw نباید جایی از برنامه فراخونده بشن.

چرخش و جابجا کردن شکل‌ها

توی مثال بعد می‌خوام از تابع‌های آماده p5.js استفاده کنم و یه شکلی رو بچرخونم؛ ببینید این کار چطوری انجام می‌شه:

function setup() {
     createCanvas(windowWidth, windowHeight)
     rectMode(CENTER)
     angleMode(DEGREES)
     noStroke()
}
function draw() {
     background(220)
     fill(237, 34, 93)

     // rotating the shape
     translate(windowWidth/2, windowHeight/2)
     rotate(45)
     rect(0, 0, 100, 100)

}
یک مربع که چرخیده شده است.

از پارامتر CENTER توی تابع rectMode استفاده کردم تا مشخص کنم مربع باید از وسط شروع به کشیده شدن کنه؛ توی p5.js مستطیل‌ها و مربع‌ها به صورت پیش‌فرض از گوشه خودشون شروع به کشیده‌شدن می‌کنن، برای همین من از rectMode استفاده کردم تا مربع از وسط خودش کشیده بشه.

همچنین از پارامتر DEGREES توی تابع angleMode استفاده کردم تا مشخص کنم زاویه‌ها با چه واحدی اندازه‌گیری بشن؛ توی p5.js زاویه‌ها به صورت پیش‌فرض از واحد رادیان استفاده می‌کنن، که من اونو به درجه یا DEGREES تغییر دادم.

از تابع translate استفاده کردم تا نقطه مبدأ (یا همون صفر و صفر) رو به وسط صفحه منتقل کنم؛ این یعنی وقتی یه شکل کشیده بشه، اون شکل در وسط صفحه قرار می‌گیره. بعد از تابع rotate استفاده کردم تا شکل رو بچرخونم و در نهایت، خود مربع رو کشیدم؛ دقت کنید همون طوری که قبل‌تر اشاره کردم، تابع translate نقطه صفر و صفر بوم شما رو از بالا سمت چپ جابجا می‌کنه و به نقطه جدیدی که شما تعیین می‌کنید تغییر می‌ده؛ از این جا به بعد، همه مختصاتی که وارد می‌کنید نسبت به این نقطه صفر و صفر جدید تعیین می‌شه؛ برای همینه که تابع rotate بعد از تابع translate فراخونی شده، چون چرخش باید نسبت به مبدأ مختصات جدید انجام بشه وگرنه نتیجه‌ای که مورد نظر ما بوده به دست نمیاد؛ برای این که بهتر متوجه بشید، فرض کنید می‌خوایم چهار تا مربع جدید اطراف این مربع بکشیم. دیگه لازم نیست مربع‌های بعدی رو بچرخونید، بلکه فقط کافیه مختصات مربع‌های جدید رو نسبت به مبدأ مختصات مشخص کنید:

function setup() {
     createCanvas(windowWidth, windowHeight)
     rectMode(CENTER)
     angleMode(DEGREES)
     noStroke()
}
function draw() {
     background(220)
     fill(237, 34, 93)

     // rotating the shape
     translate(windowWidth/2, windowHeight/2)
     rotate(45)
     rect(0, 0, 100, 100)
     rect(110, 0, 100, 100)
     rect(0, 110, 100, 100)
     rect(0, -110, 100, 100)
     rect(-110, 0, 100, 100)

}
چند مربع که چرخیده شده اند.

پوش و پاپ

حالا اگه دوست نداشتیم این طور باشه چی؟ یعنی بخوایم یه بخش از کد، فارغ از تنظیمات بخش‌های دیگه کار کنه چی؟ در این صورت باید اون بخش رو بین تابع‌های push و pop بنویسیم؛ این طوری برای کدی که بین این دو تابع نوشته می‌شه یه وضعیت جدید به وجود میاریم؛ دقت کنید که این دو تابع هم از توابع آماده p5.js هستن:

function setup() {
     createCanvas(windowWidth, windowHeight)
     rectMode(CENTER)
     angleMode(DEGREES)
     noStroke()
}
function draw() {
     background(220)
     fill(237, 34, 93)

     // rotating the shape
     push()
     translate(windowWidth/2, windowHeight/2)
     rotate(45)
     rect(0, 0, 100, 100)
     pop()
  
     // new squares
     rect(110, 0, 100, 100)
     rect(0, 110, 100, 100)
     rect(0, -110, 100, 100)
     rect(-110, 0, 100, 100)

}
چند مربع در صفحه به شکل پراکنده قرار گرفته اند.

همون طور که می‌بینید، تنظیماتی که بین تابع‌های push و pop نوشته شده، روی مربع‌های دیگه اعمال نشده و اصطلاحاً این بخش از کد، ایزوله شده. تابع‌های push و pop همیشه با همدیگه استفاده می‌شن؛ استفاده کردن از یکی از این توابع و استفاده نکردن از اون یکی، هیچ معنایی نداره و تأثیری هم توی برنامه‌تون نمی‌ذاره.

ارسال نظر

ایمیل شما منتشر نخواهد شد. بخش‌های ضروری با * مشخص شده‌اند.