فصل ششم: توابع در اکما اسکریپت

07 شهریور 1397
es6-functions-1

توابع بلوک هایی از کدهای برنامه نویسی هستند که قابلیت استفاده مجدد در سراسر برنامه دارند. توابع توسط کلمه کلیدی function تعریف می شوند. نحوه تعریف یک تابع استاندارد به شکل زیر است:

function function_name() { 
   // function body 
}

برای اجرای یک تابع، باید آن را فراخوانی کرد. به اینکار فراخوانی تابع می گویند. نحوه فراخوانی یک تابع مانند زیر است:

function_name()

مثال: تعریف یک تابع ساده

//define a  function 
function test() { 
   console.log("function called") 
} 
//call the function 
test()

مثال بالا یک متد به نام test() را ایجاد می کند. کدهایی که بین علامت های {} قرار دارند، بدنه تابع و همچنین قلمرو تابع می گویند. یک تابع برای اجرا حتما باید فراخوانی شود.

خروجی کد بالا:

function called

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

توابع می توانند به نوع های برگشت دهنده و پارامتری تقسیم شوند.

توابع برگشت دهنده

توابعی که بعد از اجرای کدهای بدنه خود، یک مقداری را به برنامه فراخوان بر می گردانند را توابع برگشت دهنده می گویند.

نحوه تعریف این نوع توابع عبارت است از:

function function_name() { 
   //statements 
   return value; 
}

در انتهای این نوع از توابع باید از کلمه کلیدی return استفاده کرد.

یک تابع فقط می تواند یک مقدار را برگرداند.

عبارت return باید در انتهای تابه نوشته شود.

کدهای زیر نحوه استفاده از دستور return را نمایش می دهد.

function retStr() { 
   return "hello world!!!" 
}  
var val = retStr() 
console.log(val)

در کد بالا، یک تابع تعریف کرده ایم که مقدار رشته ای hello world را بر می گرداند.

خروجی کدهای بالا

hello world!!!

توابع پارامتری

پارامترها مکانیزمی برای ارسال مقادیر به تابع هستند. پارامترها بخشی از امضای تابع می باشند.

در طی اجرای یک تابع پارامترها به آن پاس داده می شوند. تعداد پارامترهایی که به یک تابع پاس داده می شوند باید با تعداد پارامترهای هنگام تعریف یک تابع برابر باشند.

کد زیر نحوه تعریف تابع پارامتری را نشان می دهد:

function func_name( param1,param2 ,…..paramN) {   
   ...... 
   ...... 
}

مثال: توابع پارامتری

در مثال زیر یک تابع تعریف کردیم که دو پارامتر به نام های n1 و n2 را گرفته و آنها را با هم جمع و نتیجه را در خروجی نمایش می دهد، و در زمان اجرا تابع، مقادیر به آن پاس داده می شود.

function add( n1,n2) { 
   var sum = n1 + n2 
   console.log("The sum of the values entered "+sum) 
} 
add(12,13)

خروجی

The sum of the values entered 25

پارامترهای پیش فرض تابع

در ES6 یک تابع اجازه می دهد که پارامترهایش مقدار اولیه بگیرند و در صورتی که در هنگام اجرا هیچ پارامتری به عنوان ارسال نشد، تابع از همان مقدار اولیه یا پیش فرض استفاده می کند.

کدهای زیر راببینید:

function add(a, b = 1) { 
   return a+b; 
} 
console.log(add(4))

در تابع بالا، به پارامتر b مقدار پیش فرض 1 را داده ایم و در صورتی که در هنگام اجرای تابع به طور صریح مقداری برای پارامتر b ارسال نشود، تابع از همان مقدار پیش فرض یعنی 1 استفاده می کند.

خروجی

5

درصورتی که به طور صریح مقداری برای تابع ارسال شود، تابع به جای استفاده از مقدار پیش فرض از همان مقداری که پاس داده شده استفاده می کند.

function add(a, b = 1) { 
   return a + b; 
} 
console.log(add(4,2))

در کد بالا، بطور صریح مقدار 2 را برای پارامتر b ارسال کردیم، بنابراین تابع از این مقدار به جای مقدار پیش فرض استفاده می کند.

خروجی عبارت است از:

6

پارامترهای Rest

پارامترهای Rest همانند آرگومان های متغیر در جاوا هستند. پارامترهای Rest تعداد مقادیری که یک تابع می تواند به آن ارسال کند را محدود نمی کند.

اگر چه تمام مقادیر ارسال شده باید از یک نوع باشند.به عبارت دیگر پارامترهای rest به عنوان یک placeholder برای چندین آرگومان از یک نوع مورد استفاده قرار می گیرد.

برای تعریف یگ پارامتر rest باید قبل از نام پارامتر سه تا نقطه قرار دهیم که به آن عملگر spread هم گفته می شود.

در کد زیر نحوه انجام اینکار را می بینید.

function fun1(...params) { 
   console.log(params.length); 
}  
fun1();  
fun1(5); 
fun1(5, 6, 7);

خروجی کد بالا:

0 
1 
3

تذکر مهم: دقت داشته باشید که پارامترهای rest باید در انتهای لیست پارامترهای یک تابع قرار بگیرند.

توابع بی نام

توابعی که هیچ شناسه ای به آن اختصاص داده نشده، توابع بی نام می گویند. این توابع به طور دینامیک در هنگام اجرا اعلان می شود.

این توابع همانند توابع استاندارد ورودی هایی را گرفته و مقادیری را در خروجی به ما بر می گردانند. هنگام تعریف یک تابع بی نام، معمولاً نمی توان مستقیم به آن دسترسی داشت، بلکه باید این توابع را به یک متغیر نسبت دهید.

نحوه تعریف یک تابع بی نام مانند زیر است:

var res = function( [arguments] ) { ... }

مثال: تابع بی نام

var f = function(){ return "hello"} 
console.log(f())

خروجی

hello

مثال: تابع بی نام پارامتری

var func = function(x,y){ return x*y }; 
function product() { 
   var result; 
   result = func(10,20); 
   console.log("The product : "+result) 
} 
product()

خروجی

he product : 200

سازنده تابع

دستور function تنها روش تعریف یک تابع نیست، بلکه شما می توانید توابع را با متد سازنده Function هم تعریف کنید. نحوه تعریف یک تابع را با استفاده از سازنده Function همراه با اپراتور جدید را در زیر می بینید:

var variablename = new Function(Arg1, Arg2..., "Function Body");

متد سازنده Function() تعدادی آرگومان رشته ای میگیرد. آرگومان آخر بدنه تابع را مشخص می کند که شامل کدهای جاوا اسکریپت است و هر دو دستور با یک دستور سمی کولن از هم جدا می شوند

سازنده Function هیچ آرگومانی را برای متدی که آنرا ایجاد کرده، ارسال نمی کند.

var func = new Function("x", "y", "return x*y;"); 
function product() { 
   var result; 
   result = func(10,20); 
   console.log("The product : "+result)
} 
product()

در مثال بالا، از سازنده Function برای تعریف یک تابع بی نام استفاده کردیم. این تابع دو پارامتر گرفته و یک product را به عنوان خروجی بر می گرداند.

خروجی

The product : 200

بازگشت و توابع جاوا اسکریپت

Recursion یا الگوریتم بازگشتی زمانی اتفاق می افتد که یک متد خود را به کرات صدا بزند. به متدی که خود را فراخوانی می کند، در اصطلاح تابع recursive یا بازگشتی می گویند.

مثال - بازگشتی

function factorial(num) { 
   if(num<=0) { 
      return 1; 
   } else { 
      return (num * factorial(num-1)  ) 
   } 
} 
console.log(factorial(6))

در مثال بالا تابع خودش را فراخوانی کرده است. خروجی کد بالا:

720

مثال تابع بازگشتی بی نام

(function() { 
   var msg = "Hello World" 
   console.log(msg)
})()

در کد بالا می بینید که یک تابع خودش را توسط یک جفت پرانتز () فراخوانی کرده است.

خروجی بالا

Hello World

توابع لامبدا

لامبدا ارجاعی به توابع بی نام در برنامه نویسی است. توابع لامبدا یک مکانیزم کوتاه برای نمایش توابع بی نام هستند.

به این توابع Arrow function هم گفته می شود

آناتومی توابع لامبدا

توابع لامبدا از سه بخش تشکیل شده است.

  • پارامترها: یک تابع به طور اختیاری می تواند شامل پارامتر باشد
  • علامت arrow/lambda (=>) : این علامت را "می رود به سمت عملگر" بخوانید.
  • دستورات: بدنه تابع را نمایش می دهد.

نکته: بطور قراردادی، از پارامتر تک حرفی برای اعلان دقیق و فشرده تابع استفاده می شود.

عبارت لامبدا

عبارت لامبدا یک روش تابع بی نام است که در یک خط انجام می گیرد

([param1, parma2,…param n] )=>statement;

مثال – عبارت لامبدا

var foo = (x)=>10+x 
console.log(foo(10))

مثال بالا روش تعریف یک متد لامبدا را نمایش می دهد. این تابع عدد 10 را با پارامتری که به این تابع پاس داده شده است، جمع می کند و نتیجه را بر می گرداند.

خروجی

20

دستورات لامبدا

نوعی تعریف توابع بی نام است که در آن بدنه تابع حاوی چندین خط کد بوده و همه آنها تشکیل یک بلوک می دهند.

( [param1, parma2,…param n] )=> {       
   //code block 
}

مثال – دستورات لامبدا

var msg = ()=> { 
   console.log("function invoked") 
} 
msg()

ارجاعی از تابع برگشت داده شده در متغیر msg ذخیده می شود.

خروجی کد بالا:

unction  invoked

انواع سینتکس

قرار دادن پرانتز برای تابعی که یک پارامتر دارد اختیاری است.

var msg = x=> { 
   console.log(x) 
} 
msg(10)

علامت آکولاد { } برای توابعی که یک دستور دارند اختیاری است.

var disp = ()=>console.log("Hello World") 
disp();

نمایش یک تابع در برابر اعلان تابع

نمایش تابع و اعلان تابع به یک معنی نیستند. بر خلاف نمایش یک تابع، اعلان یک تابع توسط نام تابع انجام می شود.

تفاوت اساسی بین این دو در این است که اعلان تابع قبل از اجرای آن تفسیر (پردازش) می شود، اما نمایش تابع موقعی پردازش می شود که موتور جاوا اسکریپت با آن در هنگام اجرا برخورد داشته باشد.

هنگامی که مفسر جاوا اسکریپت با یک تابع در کد اصلی برنامه برخورد کند، فرض می کند که یک اعلان تابع رخ داده است. اما هنگامی که یک تابع در بخشی از یک دستور ظاهر شود، به عنوان نمایش تابع تفسیر می شود.

Function Hoisting

Hoisting در واقع به یک رفتار پیش فرض زبان جاوا اسکریپت اطلاق می گردد. این رفتار عبارت است از انتقال خودکار تعریف متغیر (variable declaration) به بالای حوزه (scope) جاری.

در جاوا اسکریپت این امکان وجود دارد که یک متغیر را پیش از اینکه تعریف شود بکار برد. به عبارتی دیگر می توان متغیر را مورد استفاده قرار داده، بعدا آن را تعریف کرد.

همانند متغیرها، توابع هم می توانند hoist شوند. بر خلاف متغیرها، هنگامی که اعلان یک تابع hoist شود، تعریف تابع hoist می شود نه نام تابع.

کد زیر نحوه hoist کردن یک تابع در جاوا اسکرپیت را نشان می دهد.

hoist_function();  
function hoist_function() { 
   console.log("foo"); 
}

خروجی

foo

اگر چه عبارت یک تابع نمی تواند hoist شود.

hoist_function(); // TypeError: hoist_function() is not a function  
var hoist_function() = function() { 
   console.log("bar"); 
};

فراخوانی فوری یک تابع

فراخوانی فوری یک تابع (IIFEs) می تواند برای جلوگیری از hoist متغیر از داخل بلوک استفاده می شود. اینکار اجازه می دهد دسترسی عمومی به متدها داشته باشیم در حالی که متغیرهای داخل تابع را هم بصورت خصوصی نگه داریم.

این الگو توابع بی نام خود - اجرا هم نامیده می شود. کد زیر این مفهوم را بهتر توضیح می دهد.

مثال 1 - IIFE

var main = function() { 
   var loop = function() { 
      for(var x = 0;x<5;x++) {
         console.log(x); 
      } 
   }(); 
   console.log("x can not be accessed outside the block scope x value is :"+x); 
} 
main();

مثال 2 - IIFE

var main = function() { 
   (function() { 
      for(var x = 0;x<5;x++) { 
         console.log(x); 
      } 
   })(); 
   console.log("x can not be accessed outside the block scope x value is :"+x); 
} 
main();

خروجی کدهای بالا:

0 
1 
2 
3 
4 
Uncaught ReferenceError: x is not define

توابع Generator

هنگامی که یک تابع معمولی فراخوانی شود، کنترل برنامه تا زمانی که تابع یک مقدار را برگرداند (return)، به تابع فراخوانی شده منتقل می شود.

با Generatorها در ES6، تابع فراخوان کنترل اجرای تابع فراخوانی شده را بر عهده می گیرد.

تابع Generator همانند تابع معمولی است با این تفاوت که:

  • تابع می تواند در هر نقطه توسط yield کنترل را به فراخوان برگرداند
  • هنگامی که یک Generator را فراخوانی می کنید، این تابع همانند تابع معمولی اجرا نمی شود، بلکه تابع Generator یک Iterator را بر میگرداند که می توانید با متد next() در بین عناصر آن پیمایش کنید.
  • Generatorها با یک علامت ستاره(*)که بعد از کلمه کلیدی function قرار می گیرد، مشخص می شوند و بقیه سینتکس آن مشابه توابع معمولی است.

مثال زیر را ببینید:

"use strict" 
function* rainbow() { 
   // the asterisk marks this as a generator 
   yield 'red'; 
   yield 'orange'; 
   yield 'yellow'; 
   yield 'green'; 
   yield 'blue'; 
   yield 'indigo'; 
   yield 'violet'; 
} 
for(let color of rainbow()) { 
   console.log(color); 
}

Generatorها یک ارتباط دو طرفه بین فراخوان و تابع فراخوانی شده برقرار می کنند. اینکار توسط کلمه کلیدی yield انجام می شود.

مثال زیر را ببینید:

function* ask() { 
   const name = yield "What is your name?"; 
   const sport = yield "What is your favorite sport?"; 
   return `${name}'s favorite sport is ${sport}`; 
}  
const it = ask(); 
console.log(it.next()); 
console.log(it.next('Ethan'));  
console.log(it.next('Cricket'));

روش کار یک تابع Generator مطابق زیر است:

  • Generatorها در یک وضعیت توقف و یک Iterator را بر می گرداند.
  • متد next() پس از برخورد با کلمه کلیدی yield توقف کرده و رشته what is your name را بر می گرداند.
  • فراخوانی next(“Ethan”) باعث می شود ه مقدار Ethan به متغیر name نسبت داده شود و سپس عبارت what is your favorite sport? چاپ می شود.
  • فراخوانی next(“Cricket”) مقدار cricket را به متغیر sport نسبت داده و دستور بعدی را بر می گرداند.

خروجی کدهای بالا:

{ 
   value: 'What is your name?', done: false 
} 
{ 
   value: 'What is your favorite sport?', done: false 
} 
{ 
   value: 'Ethan\'s favorite sport is Cricket', done: true 
}

نکته: توابع Generator نمی توانند توسط arrow function نمایش داده شوند.

نویسنده شوید

دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.