接著來到 TodoList v2.0,今天我們來加點函數小菜!
在這可能就有很多初學者跟我一樣的黑人問號??!!
Q1:什麼是函數?什麼是函式?
A1:接下來本篇會教到一個新的名詞和用法,也就是 Function ,台灣翻譯叫「函數」、大陸翻譯「函式」,這裡我們統一以台灣版翻譯為主。
Q2:為何要使用函數(Function)?
A2:大部分的專案裡面都會存在著很多重複性的步驟,以 TodoList 來說:
今天上午新增一個 A、B、C 事項,然後下午修改了 B 事項,後來 A 事項被取消了,所以刪除。隔天在新增 D、E 事項,接著不久又修改 C、D 事項和刪除 E 事項。
(這時候就會看到工程師的經典表情...)
不論上述事項怎麼增增減減或修改,都還是依循著上一篇提到的5大主功能(儲存、顯示、新增、修改、刪除)在運作,只是把運作中的主角換掉。
如果用原先的程式碼來處理上述的工作,那工程師們可能都想撞牆了,因為都是一堆重複性的工作,無限的複製貼上,程式碼也不知道會爆出幾百幾千行,更別說超難維護與除錯的肥大檔案會造成網頁多大的負擔。既然重工在工程師們的眼裡是個毒瘤,那麼可以解救這些悲慘工程師來處理這些重複性的工作,就是非 Function(函數) 莫屬了。
函數是構成 javascript的基本要素之一。一個函數本身就是一段 JavaScript程式,包含用於執行某一個任務或計算的語法。要呼叫某一個函數之前,你必須先在這個函數想要執行的 scope 中定義它。
簡單來說:
就是把一段或多段的重複指令包起來,等到需要的時候呼叫它,以方便重複執行相同的任務。
所以本篇的學習重點,就是把上一篇的指令全部函數化之後,再呼叫執行而已。
Function(函數) 的宣告方法有好幾種
- 函數宣告 Function Declaration
- 函數運算式 Function Expression
- 函數關鍵字 Function Keyword
這裡僅先以「函數宣告 Function Declaration」來使用和解說,若有興趣研究其他方法的同學請往這走,或是直接拉到文章最下方也有推薦參考文 ↓↓↓↓↓
- 定義 JavaScript 函數(Functions)的各種方式 - by G.T.Wang
- 重新認識 JavaScript: Day 10 函式 Functions 的基本概念 - by Kuro Hsu
- 覺得 JavaScript function 很有趣的我是不是很奇怪 - by 胡立
函數宣告寫法:
function myFunction(){
.....
}
function 函數名稱 (參數1, 參數2, 參數3, ...) {
// 要執行的程式代碼
// 返回值 return
}
JS 白話文:
- 用
function
來宣告一個函數,後面加上自取的函數名稱(如:myFunction
、myName
...)。當然函數也可以沒有名稱,只是寫法不是這樣。沒有名字的函數在 JS 是合法的,通常我們稱它為「匿名函數」,這個暫時不是本文的討論範圍,以後等我心情好XD有空就會另寫一篇關於函數的詳細討論。 - 小括號
()
中的內容,稱為參數(function parameters),多個參數則用逗號,
隔開。如果不需要參數,小括號內空白就好,但不可省略,例:function myName()
- 大括號
{}
內的內容,則是要執行的程式代碼,可用return
這個功能,來返回指定的值給調用的參數,同時程式也會停止繼續執行,若不用return
的話則會返回undefined
。
說了一堆聽不懂的,還是來個範例比較好理解。下方是早餐店漢堡的食譜,我們寫成函數試試看:
//牛肉漢堡
function HamburgerWithBeef(){
step1 = 'get one bread'; //第一步:放一片麵包
step2 = 'add Cheese'; //第二步:加起司
step3 = 'add Beef'; //第三步:牛肉放起來
step4 = 'put a pice of bread on top'; //第四步:再放一片麵包在上面
}
換成豬肉漢堡試試看:
//豬肉漢堡
function HamburgerWithPork(){
step1 = 'get one bread'; //第一步:放一片麵包
step2 = 'add Cheese'; //第二步:加起司
step3 = 'add Pork'; //第三步:豬肉放起來
step4 = 'put a pice of bread on top'; //第四步:再放一片麵包在上面
}
再換成雞肉漢堡:
//雞肉漢堡
function HamburgerWithChicken(){
step1 = 'get one bread'; //第一步:放一片麵包
step2 = 'add Cheese'; //第二步:加起司
step3 = 'add Chicken'; //第三步:雞肉放起來
step4 = 'put a pice of bread on top'; //第四步:再放一片麵包在上面
}
買尬!如果你是老闆,會不會覺得怎麼那麼煩,有夠多重複的工作方式,如果來個機器人員工幫忙製作就好了...
沒錯,函數就是來解決老闆們的煩惱,讓我們先找出哪裡不一樣!
看來似乎都是肉肉搞的鬼,這些要替換的肉類其實就是我們上面所講到的「參數(function parameters)」,但是參數要放在小括號裡面阿,所以我們稍微修改一下程式內容,把會變動的字改放到小括號內,我們取個參數名叫 meat
好了。
function HamburgerWith(meat){
step1 = 'get one bread'; //第一步:放一片麵包
step2 = 'add Cheese'; //第二步:加起司
step3 = 'add' + meat; //第三步:肉肉放起來
step4 = 'put a pice of bread on top'; //第四步:再放一片麵包在上面
}
宣告完啦!就這麼簡單幾句就可以完成製作各種漢堡的統一條件,但...這只是做完漢堡而已,都還沒到客人手中啊,這時就要用到 呼叫函數 來出餐了。
呼叫函數(Calling function)
宣告完的函數並不會自動的執行,你必須呼叫函數,才會執行函數的內容。
寫法:
函數名稱(參數);
所以做完的漢堡出餐的執行方式就會是這樣...
HamburgerWith(Beef); //牛肉漢堡
HamburgerWith(Pork); //豬肉漢堡
HamburgerWith(Chicken); //雞肉漢堡
以上就是函數的概念,是不是簡單很多。
回到我們的 TodoList 專案,v2.0 版就是把上一篇寫的 code 全部函數化,以方便呼叫重複執行的指令。
先回憶一下上一版 v1.0 的 TodoList 長這樣:
// 1.儲存代辦清單內的陣列資料
var todos = ['item1','item2','item3'];
// 2.顯示代辦清單
console.log(todos);
// 3.新增新的項目
todos.push('newItem');
// 4.更改陣列內的值
todos[0] = 'updated';
// 5.刪除項目
todos.splice(2, 1);
修改為函數化寫法:
1. 儲存代辦清單:
因為是宣告所有的代辦清單,所以這行不用動
2. 顯示代辦清單:
function showTodos() {
console.log('My todos: ', todos);
};
JS 白話文:
- 取名一個函數名
showTodos
,此項還用不到參數,所以小括號內容空白就好()
。 console.log
的內容稍微美化一下,改放字串'My todos: '
和變數名todos
,主要是為了讓最後印出的資料看起來更好理解
呼叫函數
showTodos();
- 因沒設定參數,所以後方的小括號
();
保持空白 - 印出 My todos: ['item1','item2','item3']
3. 新增新的項目:
function addTodos(newTodos) {
myTodos.push(newTodos);
showTodos();
};
JS 白話文:
- 取名一個函數名
addTodos
,小括號內的參數先保持空白()
,等下再回頭處理它。 - 把「1.新增項目」的
myTodos.push('new item');
那行搬過來。小括號內'new item'
是會隨著新增的名稱而任意變動,所以並不能以固定字串呈現,所以改為變數並取名為newTodos
。(注意:變數名稱不可加上單引號或雙引號,否則又會變回字串。) - 回到上一行
function addTodos()
,小括號內的參數要填入剛剛的變數newTodos
,這樣函數內外都有相同變數名稱,才能取值調用,並正確執行函數內容。 - 下一行加上
showTodos();
來執行上面的程式。
呼叫函數
addTodos('do my homework');
- 小括號內並寫入要新增的項目名稱,如
'do my homework'
- 印出 My todos: ['item1','item2','item3', 'do my homework'],可以發現最後面被添加了新的項目
'do my homework'
4. 更改陣列內的值:
function changeTodo (position, updatedName) {
todos[position] = updatedName;
showTodos();
};
JS 白話文:
- 同樣我們並不知道使用者想要修改第幾個代辦事項或改成什麼名稱,於是
function
後的小括號內 2個參數,都要改為變數,參數1(修改位置)取名為position
。參數2(修改後的名稱)取名為updatedName
。 - 把「4.更改陣列」
todos[0] = 'updated';
那行搬過來。中括號[0]
內指的是修改位置,和上方的參數1position
相同,接著=
右方是修改後名稱,也和上方參數2updatedName
相同,這樣才可正確的取到值並調用修改原有的清單項目內容。 - 下一行加上
showTodos();
執行程式。
呼叫函數
changeTodo(1, 'take a rest');
- 小括號內並寫入參數,參數一是數字 1(指的是第二個位置的清單項目
'item2'
),參數二是修改後名稱,如'take a rest.'
。 - 如果用
console.log
則印出 My todos: ['item1','take a rest','item3', 'do my homework'],可以發現第二項的'item2'
已經被修改為'take a rest'
5. 刪除項目:
function deleteTodo(position) {
todos.splice(position, 1);
showTodos();
};
先回憶一下Array的刪除指令用法 .splice(index, howmany, item1, ....., itemX)
,小括號內包含了:
1.第一個參數 index(必填):指定新增或刪除的序列號碼
2.第二個參數 howmany(選填):從指定新增或刪除的位置起算,共要移除幾筆資料
3.第三個參數 item1,.....,itemX(選填):為新增或修改後的內容(字串要加上單或雙引號),這裡不需要所以不填
JS 白話文:
- 因為是刪除清單項目,這裡函數
function
的小括號()
,只需要第一個參數值,也就是變數position
,因為沒有要修改或異動項目名稱,當然也就不需要參數2, - 為了可以正確取到變數
position
的值,在使用刪除指令時,.splice()
的第 1個參數,就填入這個變數position
,而不是清單項目的位置。 - 而第二個參數就維持數字 1 不變,因為目前一次只會刪除一個代辦事項。
- 第三個參數一樣不需要新增或修改,所以不填。
- 下一行加上
showTodos();
執行程式。
呼叫函數
deleteTodo(0);
- 小括號內並寫入參數 0 (指的是刪除第一個位置的清單項目)
- 如果用
console.log
則印出 My todos: ['take a rest','item3', 'do my homework'] ,可以發現第一項的'item1'
已經不見了。
終於結束了鬼打牆的程式解說,一樣幫各位統整一下剛剛 v2.0 的程式碼
// 1.儲存代辦清單內的陣列資料
var todos = ['item1','item2','item3'];
// 2.顯示代辦清單
function showTodos() {
console.log('My todos: ', todos);
};
// 3.新增新的項目
function addTodos(newTodos) {
myTodos.push(newTodos);
showTodos();
};
// 4.更改陣列內的值
function changeTodo (position, updatedName) {
todos[position] = updatedName;
showTodos();
};
// 5.刪除項目
function deleteTodo(position) {
todos.splice(position, 1);
showTodos();
};
這篇我們學習到具名函數的結構和表達方式,以及如何取值調用。不過這裡只是函數領域的冰山一角,它還有很多更細節的領域可以去探索。本文僅提供施作 ToDoList 專案的功能代碼介紹而已,不多詳加贅述關於函數的其他功能,如果你有興趣,可以看下方的參考資料,或是多去爬文了解,也許可以更帶領你增進許多關於函數的知識。
感謝你耐心看完本文,請到後台跟我領取乖寶寶貼紙一枚 =3= 啾
本文學習參考資料: