تعداد بازدید: 233

توابع در جاوا اسکریپت (قسمت اول)

یک تابع یک بلوک کد است که یک وظیفه خاص را انجام می دهد (block of code do specific task). از این جهت بسیار شبیه به procedure می باشد با این تفاوت که تابع می تواند ورودی و خروجی input/output داشته باشند. procedure متشکل از تعدادی statement می باشد که یک هدف خاص را دنبال می کند و منجر به انجام یک task خاص می شود.

A procedure is a block of code (chained statemetns) that perform a task

A function is a block of code that  perform a task have input/output

global scope

هر تابع که در global scope تعریف شده باشد یک متد از متغیر window است مگر این که در یک module تعریف شده باشد که لازم است به صورت دستی به window اتصال پیدا کند. پس متغیر هایی که در global scope تعریف شده باشند در توابع global scope قابل دستیابی و تغییر می باشند. متغیرهایی که در global scope تعریف شده باشند به عنوان یک attribute از متغیر window است و انگار متدی یک attribute را تغییر داده است.

function test(){
  console.log('it work')
}
window["test"] //function test()
window["test"]() //it work

Function scope

هر تابع در زمان تعریف یک scope اختصاصی در خود ایجاد می کند که در آن اگر متغیری تعریف گردد در سایر global scope قابل دستیابی است . در صورتی که یک تابع به صورت nested تعریف شده باشد scope های داخلی به scope های بالایی دسترسی خواهند داشت و scope های بالایی به scope های داخلی دسترسی نخواهند داشت.

var a = 10
function test(){
  a++
}
console.log(a) //10
test()
console.log(a) //11
var person = {
    'name' : 'ali',
    'famil' : 'alavi'
}
function hello(person){
    person.name = 'ahmad'
    console.log(person.name)
}
hello(person) //"ahmad" 
person.name //"ahmad"

مطابق با بلوک کد زیر scope بالایی به scope پایینی دسترسی ندارد و متغیر local تعریف شده در تابع test در global scope تعریف نشده است.

function test(){
  var b = 10
}
console.log(b) //Uncaught ReferenceError: b is not defined

Defining (Declare) Function

برای تعریف یک تابع روش های مختلفی داریم که هر یک از این روش ها کاربردهای اختصاصی خود را دارند و در جایگاه خاص استفاده می شوند. به طور مثال در تعریف callback هایی که در داخل یک کلاس تعریف شده اند بهتر است برای دسترسی به this (شئ داخلی کلاس و ویژگی های آن ها ) از Arrow function استفاده می کنیم. یا اگر قرار است یک موجودیت را تعریف کنیم که یک سری action های مرتبط دارند از Object استفاده کنیم.

function declaration key

function square(x){
   return x * x
}

طبیعتا هر تابع یک نام خواهد داشت که در بارگیری نرم افزار در حافظه RAM بتوان با آن نام به آن دسترسی داشت. توابعی فاقد نام را closure می نامیم.

تعریف تابع در global scope با نام یکسان خطایی را در مفسر به شما نخواهد داد چرا که هر یک از توابع تعریف شده یک ویژگی از متغیر جهانی window است و این مقادیر قابل بازنویسی و تغییر می باشند.

function in variable

نکته مهم در این نوع تعریف تابع این است که باید برای فراخوانی این تابع عبارت () جلوی نام متغیر قرار بدهیم.

var test = function(){
  console.log('it work')
}

test //function test()
test() //it work

Object create

var person ={
   
   setName: function(name){
      this.name = name
   },
   getName: function(){
      return this.name
  },
   setAge: function(age){
      if("number" != typeof age){
         return
      }
      this.age=age
   },
   getAge: function(){
      return this.age
   }
}
var personOne = Object.create(person)
personOne.setName('Abolfazl')
personOne.setAge(29)

این روش زمانی کاربرد دارد که بخواهیم موجودیت های خاص را به تعداد خاص از یک قالب در پروسه ای خاص تعریف کنیم . بدین ترتیب می توان یک سری اشخاص با شئ person تعریف کنیم.

function local object

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

var person = function(){
   let name,age
   const actions = {
      setName: function(requestName){
         name = requestName
      },
      getName: function(){
         return name
     },
      setAge: function(requestAge){
         if("number" != typeof requestAge){
            return
         }
         age = requestAge
      },
      getAge: function(){
         return age
      }
  	}
   return actions
}

var personOne = person()
personOne.setName('Abolfazl')
personOne.getName() //"Abolfazl"
personOne.setAge(28)
personOne.getAge() //28

روش بالا روش مطمئن تر و استاندارد تری برای ساخت موجودیت در قالب تابع می باشد . به این شکل که در خارج از تابع ما به متغیر های name , age دسترسی نداریم چرا که این متغیر ها محلی در داخل تابع هستند . و getter/setter ها به ماهیت اصلی خود بسیار نزدیک تر هستند.

Nested Function

ما می توانیم به عمق خاص توابع را در داخل هم تعریف کنیم. در این روش هر تابع یک scope خاص خود را دارد و توابع به عمق بیشتر به scope های بالاتر خود دسترسی دارند.

function sumFive(){
    const five = 5
    function sum(requestNum){
        return requestNum * five
    }
    return sum
}
sumFive()(2)
10

Arrow Function

تابعی که syntax آن به صورت یک فلش می باشد و به همین دلیل به آن arrow function می گوییم. مهم ترین مشخه این نوع تابع این است که در خود به this در بدنه خود ندارد و به this در scope بالایی اشاره می کند:

var sum = (a,b) => {
  console.log(a+b)
}
sum(10,11) //21

در صورتی که Function Body تک خطی باشد می توان به صورت shorthand آن را تعریف کرد:

sayHello = name => console.log('Hello', name);

برای فهم بهتر مشخصه اصلی arrow function به مثال زیر توجه کنید:

var objectTraditional = function(){
    let name,age
    const actions = {
      getThis: function(){
          console.log(this)
      }
    }
    return actions
}

var obj = objectTraditional()
obj.getThis() //Object { getThis: getThis() }

در خروجی متد بالا همان طور که می بینید this در این متد همان مقدار object داخلی بود . حال اگر متد getThis را به صورت arrow function تعریف کنیم  به scope اصلی اشاره می کند. به مثال زیر توجه کنید:

var objectTraditional = function(){
    let name,age
    const actions = {
      getThis: () => {
          console.log(this)
      }
    }
    return actions
}

var obj = objectTraditional()
obj.getThis() //Window

در زمانی که قرار است متدی را به صورت callback ارسال کنیم و به ویژگی های کلاس جاری دسترسی داشته باشیم بهتر از arrow function استفاده کنیم

نکته مهم : با استفاده از bind می توانیم رفتار یک تابع معمولی را به یک Arrow function تبدیل کنیم . همان طور که در مثال زیر مشاهده می کنید مقدار this به تابع getName از شئ Bind شده است .

var name = 'zidane'
var player = {
    name: 'barthez',
    getName: (function(){
        return this.name
    }).bind(this)
} 

player.getName() //'zidane'

Arrow function shorthand : یک حالت پرکاربرد () => x برابر است با () => { return x}

Function Parameters

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

  • Default Parameters : پارامتر های پیش فرض است که اگر مقدار دهی نشوند این مقادیر به صورت پیش فرض به آن ها داده می شود.
  • Rest Parameters : یک نوع syntax خاص برای دریافت پارامتر های یک تابع در بدنه آن به صورت یک object

Default Parameters

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

function hello(name='guest'){
    alert('hello ${name}')
}
hello()

Rest Parameters

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

function people(...names){
    console.log(names)
}
people('ali','mohamad','hasan','reza') //Array(4) [ "ali", "mohamad", "hasan", "reza" ]

در این روش ما می توانیم پارامتر های خاص را تا تعداد خاص دریافت کنیم و در نهایت باقیمانده را در قالب rest دریافت کنیم.

function people(seprator,...names){
    let output = '*'
    for(let name of names){
        output += name + seprator
    }
    return output
} 
people(',','ali','mohamad','hasan','reza')  // "*ali,mohamad,hasan,reza,"

نکته مهم : دقت داشته باشید rest همیشه آخرین پارامتر تعریف شده باید باشد.

Argument Object

با استفاده از کلمه کلیدی arguments (به صورت جمع) می توان کل مقادیر پارامتر های تابع را به صورت یک array-like Object دریافت کنیم. دقت داشته باشید خروجی یک arguments است و یک آرایه نیست اما مثل آرایه قابل پیمایش است:

function peoples(){
    console.log(arguments)
}
peoples('ali','mohamad','hasan','reza') //Arguments { 0: "ali", 1: "mohamad", 2: "hasan", 3: "reza", … }

نکته مهم : arguments در Arrow functions قابل استفاده نیستند.

var a = (a,b,c) => {
    console.log(arguments)
}
a(1,2,3) //Uncaught ReferenceError: arguments is not defined

مطالب مشابه

Javascript Variable Scope – Mutable

هر statement بر اساس جایگاهی از کد که در آن قرار گرفته است سطح دسترسی به سایر قسمت های کد دارد که به آن Scope می گوییم....

Modular Programming ES6

کدنویسی ماژولار یکی از فلسفه های برنامه نویسی شئ گرا است که می توان بخش های هر قسمت از یک برنامه را در یک سری ماژول...

اشتراک گذاری :

مدیر وب سایت گنوتک . برنامه نویسی رو با زبان C در هفده سالگی شروع کردم . در حال حاضر به برنامه نویسی php برپایه معماری MVC , HMVC و همچنین سیستم مدیریت محتوای WordPress و فریم ورک محبوب لاراول علاقه مند هستم و دوست دارم اطلاعاتم رو با شما به اشتراک بگذارم.

۰ دیدگاه برای توابع در جاوا اسکریپت (قسمت اول)

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *