iT邦幫忙

2021 iThome 鐵人賽

0
自我挑戰組

重新開始 JavaScript系列 第 31

[Day31] 函式

Day21 - 物件的基礎概念2 中有提到函式是物件的一個子型別,所以它本身就是一個物件,但函式又與一般的物件有些需不同,詳述如下:

函式的簡介

函式通常會包括以下內容:

  1. 函式名稱,但也可沒有( ex: 匿名函式)
  2. 小括號 (),而小括號內可以有以 逗號 , 分開的多個參數
  3. 大括號 {},大括號內為程式碼片段

以下為簡單的函式範例:

透過 關鍵字 function 來宣告一個函式,而 fun 是這個函式的名子,小括號 () 內為此函式的參數,而在 大括號 {} 內寫入程式碼片段,並可在內使用 return 使函式回傳值,最後可以利用 fun('參數');,呼叫此函式,也因 fun('參數'); 是表達式,可以回傳值,因此也可以賦予到變數上

function fun(parameter1, parameter2) {
    var local = '區域變數'
    console.log(local)
    return parameter1 + parameter2;
}
var call = fun('參數1', '參數2');
console.log(call);

而函式與一般物件的不同在於:

  1. 可以被呼叫
  2. 包含程式碼片段
  3. 函式可以有一個名稱,但也可不需要( ex: 匿名函式)

函式的類型

函式可以被分為函式陳述式與函式表達式

函式陳述式

函式陳述式又稱 具名函式,意思就是有名子的函式,可以直接利用名子呼叫函式

函式是否需要名稱,在於函式是否能夠被調用,可被調用就可省略
(ex: 當賦予到變數上,可直接使用變數呼叫,此函式就不需要定義名稱)

function fun() {
    console.log(fun);
}

fun(); // 呼叫函式陳述式

/*
ƒ fun() {
    console.log(fun);
}
*/

不能使用函式陳述式的例子:

  • 立即函式
  • 物件內的方法

函式表達式

函式表達式,是先宣告一個變數,透過 = 運算子function 宣告的函式,賦予到此變數上,而此函式不一定需要名稱,若 沒有定義函式名稱則為 匿名函式

因將函式賦予到 變數 fun 上,變數 fun 接收的是此函式的參考路徑

var fun = function () {
    console.log(fun);
}

fun(); // 呼叫函式表達式

/*
ƒ fun() {
    console.log(fun);
}
*/

當具名函式賦予到變數上,也是函式表達式,但需要注意的是在此狀況下,此具名函式只能在函式內被調用,如果在函式外調用則會出錯

var fun = function fun2() {
    console.log(fun);
    console.log(fun2);
}

fun();

/*
ƒ fun2() {
    console.log(fun);
    console.log(fun2);
}

ƒ fun2() {
    console.log(fun);
    console.log(fun2);
}
*/

fun2(); // 因在函式外調用,故出現錯誤訊息
// Uncaught ReferenceError: fun2 is not defined

函式的提升

Day7 - 提升 章節有提到關於函式的提升,在此複習一下:

函式陳述式 會在創造階段時,先在記憶體中將函式陳述式的所有內容做保留

function fn() { 
 // ...
}

fn();

運作過程:

// 1.創造階段
function fn() { 
 // ...
}

// 1.執行階段
fn();

函式表達式 創造階段時只會將它的變數先在記憶體中保留空間,直到執行階段才會將函式賦予給此變數,所以若要利用函式表達式,就必須等函式已經賦予到變數上,才能運行此函式

var fn = function () { 
 // ...
}

fn();

運作過程:

// 1.創造階段
var fn;

// 1.執行階段
fn = function () { 
 // ...
}

fn();

Airbnb 規範

在 Airbnb 的規範中,會建議盡量避免使用陳述式,使用為具名函式的函式表達式,這是為了在大型專案中,函式陳述式的提升性質可能會影響其他程式碼運行,而使用具名函式的函式表達式而非用匿名函式,則是因具名函式因具有名子能更方便除錯,以下範例取自 Airbnb 規範

// bad
function foo() {
  // ...
}

// bad
const foo = function () {
  // ...
};

// good
// lexical name distinguished from the variable-referenced invocation(s)
const short = function longUniqueMoreDescriptiveLexicalFoo() {
  // ...
};

參考文獻

六角學院 - JavaScript 核心篇


上一篇
[Day30] 完賽結語
下一篇
[Day31] 參數
系列文
重新開始 JavaScript32

尚未有邦友留言

立即登入留言