函式 (Function)
在程式設計中,函式是一段可以重複使用的程式碼,用來執行特定的任務。透過函式,我們可以讓程式更具結構性、可讀性和可維護性。
什麼是函式?
函式是一個封裝好的程式碼區塊,可以透過名稱來呼叫它,並執行其中的程式碼。
函式的好處在於:
- 重複使用:我們可以多次呼叫同一個函式,而不需要重複撰寫相同的程式碼。
- 可讀性:函式名稱可以清楚地表達其功能,讓程式碼更易於理解。
- 維護性:如果需要修改某個功能,只需修改函式內部的程式碼,而不需要在多處修改。
- 抽象化:將複雜的邏輯封裝起來,讓使用者不需要了解內部實現細節,只需關心如何使用。
- 模組化:將程式碼分成小塊,讓整體結構更清晰。
- 參數化:接受不同的輸入,讓同一個函式可以處理多種情況。
如何撰寫一個函式:function + 函式名稱 + (輸入的參數) + {函式實際執行的內容},以下是一個簡單的範例:
// 這裡是一段重複四次的程式碼
console.log(`Welcome, Alice!`)
console.log(`Hello, Bob!`)
console.log(`No, Charlie!`)
console.log(`Nice to meet you, David!`)
// 上面四個程式碼可以整理成一個函式
// 這樣就可以重複使用這段程式碼,只要傳入不同的名字即可
function sayHello(word, name){
console.log(`${word}, ${name}!`);
}
sayHello('Welcome', 'Alice'); // 輸出 "Welcome, Alice!"
sayHello('Hello', 'Bob'); // 輸出 "Hello, Bob!"
sayHello('No', 'Charlie'); // 輸出 "No, Charlie!"
sayHello('Nice to meet you', 'David'); // 輸出 "Nice to meet you, David!"在上面這段程式碼中,我們定義了一個名為 sayHello 的函式,它接受兩個參數:word 和 name。當我們呼叫這個函式時,它會輸出一個格式化的問候語。
函式回傳值
函式可以分成有回傳值和沒有回傳值兩種。
有回傳值的函式會使用 return 關鍵字來回傳一個值(結果)。
而沒有回傳值的函式則不會,只是單純的執行一些程式碼,而這類沒有回傳值的函式又稱為 void 函式。
// 這是一個會回傳兩個數字總和的函式
function add(a, b) {
return a + b;
}
console.log(add(2, 3)); // 輸出 5
// 這是一個沒有回傳值的函式,只是輸出兩個數字的總和
function printSum(a, b) {
console.log(a + b);
}
printSum(2, 3); // 輸出 5TIP
可以想像成:有回傳值的函式像是自動販賣機,投入硬幣並選擇商品時,它會回傳商品
而沒有回傳值的函式則像是一個只會發出聲音的警報器,當觸發時它會發出聲音,但不會回傳任何東西。
事實上由於 JavaScript 會對所有函式進行隱式回傳處理,在 JavaScript 中沒有回傳值的函式都會回傳 undefined,這裡先不深入討論,簡單知道即可。
函式是可以組合的
函式可以被組合起來使用的,這樣可以讓程式碼更具可讀性和可維護性。
例如說我們可以定義一個函式來計算兩個數字的總和,再使用這個函式來計算其他數字的總和。
function add(a, b) {
return a + b;
}
/**
* 當然也可以把函式組合起來一起用
* 先計算 1+2 = 3,再計算 3 + 7 = 10,
* 最後再計算 3 + 7 = 10
*
* 其實很像數學式 ( (1+2) + (3+4) ) = 10
*/
console.log(add(add(1, 2), add(3, 4)));
/**
* 也可以再複雜一點
* 計算 ( (1+2) + (3+4) ) + (5+6) = 28
* 這樣就可以把多個函式組合起來使用
*/
console.log(add(add(add(1, 2), add(3, 4)), add(5, 6)));
/**
* 上面的寫法可能會讓程式碼變得難以閱讀
* 所以也可以拆成兩行來寫,先計算前兩個,再計算後兩個
* 比較容易看懂
*/
const combined = add(add(1, 2), add(3, 4));
console.log(add(combined, add(5, 6))); // 輸出 28箭頭函式 (Arrow Function)
前面提到了一般函式的宣告方式是 function 函式名稱(參數) { 函式內容 }。
但是在 JavaScript ES6 之後,出現了一種更簡潔的函式宣告方式,稱為 箭頭函式(Arrow Function)。
寫法:const 名稱 = (參數) => { 函式內容 }。
const greet = (name) => {
return 'Hello, ' + name + '!';
};
console.log(greet('Aaron')); // 輸出 "Hello, Aaron!"
// 當函式只有一行時,可以省略大括號 `{}` 和 `return` 關鍵字
const greet = (name) => 'Hello, ' + name + '!';
console.log(greet('Aaron')); // 輸出 "Hello, Aaron!"預設參數
前面提到函式可以給定一些參數作為輸入,但有時候會希望可以有預設的參數,當函式的參數沒有傳入值時,可以使用預設參數:
function greet(name = '訪客') {
return 'Hello, ' + name + '!';
}
console.log(greet()); // 輸出 "Hello, 訪客!"
console.log(greet('Aaron')); // 輸出 "Hello, Aaron!"剩餘參數
使用剩餘參數可以接收不定數量的參數,並以陣列的方式傳入到函式中:
// ...number 會將傳入的參數收集成一個陣列
function sum(...numbers) {
let sum = 0;
for (let i = 0; i < numbers.length; i++) {
sum += numbers[i];
}
return sum;
}
console.log(sum(1, 2, 3, 4)); // 輸出 10但要特別注意的是,剩餘參數只能作為函式的最後一個參數使用,否則會報錯。
function whatYouGot(name, ...somethings){
console.log(`Hello, ${name}!`);
console.log(`You got:`, somethings);
}
// 這樣會報錯,因為剩餘參數擺在前面編譯器不知道哪個是 `name` 參數
function whatYouGot(...somethings, name){
console.log(`Hello, ${name}!`);
console.log(`You got:`, somethings);
}Function vs Arrow Function 差異
前面我們使用了兩種函式宣告方式:傳統函式宣告和箭頭函式。
雖然它們都可以用來定義函式,但有一些重要的差異:
傳統函式宣告可以被提升(hoisting),即使在函式宣告之前呼叫也不會報錯:
console.log(add(2, 3)); // 找得到 function:add
function add(a, b) {
return a + b;
}
console.log(add(2, 3)); // 錯誤,因為箭頭函式不會被提升
const add = (a, b) => a + b;TIP
提升(Hoisting)
前面提過,JavaScript 是一種直譯型語言,這意味著程式碼在執行前會被解釋器讀取並處理。
提升(hoisting)是指在 JavaScript 的編譯階段,會優先讀取 function 宣告,並將其提升到程式碼的頂部。
這意味著你可以在函式宣告之前呼叫它,而不會報錯。
像是這類會進行提升處理的有: 函式宣告(function declarations)、變數宣告(var)和類別宣告(class declarations)。
把 Function 當作變數使用
前面提到箭頭函式時,有沒有發現其實我們是宣告了一個變數並且賦予函式當作值?
對,函式本身可以被當作變數來使用。
const add = function(a, b) {
return a + b;
};
const anotherAdd = add; // 將函式指派給另一個變數
console.log(anotherAdd(5, 10)); // 輸出 15甚至可以將函式當作參數傳遞給其他函式:
function executeFunction(func, a, b) {
return func(a, b);
}
const add = (a, b) => a + b;
const subtract = (a, b) => a - b;
console.log(executeFunction(add, 5, 10)); // 輸出 15
console.log(executeFunction(subtract, 10, 5)); // 輸出 5小結
函式是程式設計中非常重要的概念,學會如何宣告、呼叫函式,以及使用參數、回傳值,能讓你的程式更具結構性與靈活性。
之後觀念更加完善之後,可以進一步探討函式的其他特性,例如作用域、閉包等。
現在試著自己動手撰寫一些函式,練習這些概念吧!
範例練習
請寫一個函式
multiply,可以回傳兩個數字的乘積。javascript// 請在這裡完成 multiply 函式 function multiply(a, b) { // ... } console.log(multiply(3, 4)); // 預期輸出 12請寫一個函式
greet,接收一個名字參數,並回傳Hello, 名字!的字串。javascript// 請在這裡完成 greet 函式 function greet(name) { // ... } console.log(greet('Eve')); // 預期輸出 Hello, Eve!請寫一個函式
sumAll,可以接收任意數量的數字,並回傳總和。javascript// 請在這裡完成 sumAll 函式 function sumAll(...numbers) { // ... } console.log(sumAll(1, 2, 3, 4)); // 預期輸出 10請將下列匿名函式改寫成箭頭函式(Arrow Function):
javascriptconst square = function(x) { return x * x; }; // 請改寫成箭頭函式請寫一個函式
isAdult,接收一個年齡參數,若大於等於 18 歲回傳true,否則回傳false。javascript// 請在這裡完成 isAdult 函式 function isAdult(age) { // ... } console.log(isAdult(20)); // 預期輸出 true console.log(isAdult(15)); // 預期輸出 false
