函式這部分整理很多容易忽略的重要語法細節,可以常看。
基本語法
函式表示某個重用流程的封裝(encapsulation)
函式定義與呼叫
- 函式定義
- function declaration 函式宣告
- JS engine會優先處理函式宣告
- function literal 函式實字
- 一種expresstion
- 執行運算式之後才產生function object
- 可附加/不附加函式實字的函式名稱
- Anonymous function 匿名函式:不附加函式名稱
- 附加函式名稱通常是為了遞迴
- Arrow function 箭頭函式
- function declaration 函式宣告
- IIFE(immediately invoked function expression)
(function(){...})();
- 外層兩個括號的前面一個
()
只是為了區分function
和後面的()
operator,例如:(45).toExponential()
JS不支援函式重載(overload)(可設定參數預設值避免)
function sum(a, b){ reutrn a + b; } function sum(a, b, c){ // 覆蓋前一個 sum() reutrn a + b + c; } console.log(sum(1, 2)); // NaN, ∵ c 是 undefined
return
- 預設回傳
undefined
:- 所以沒有
return
或return
不指定傳回值就會回傳undefined
- 所以沒有
陳述句可不用
;
結束判定,但可能造成某些問題:// bad.js function foo(){ return // 會在這行直接離開函式並跳回函式呼叫處 { x: 10 } } console.log(foo()); // undefined // good.js function foo(){ return { x:10 }; }
- 所以在 JS 千萬不要跟以下範例 bad.js 相同讓
{
和}
在同一縮排(以免以為 換行 代表結束)
- 預設回傳
Fitst-class function 一級函式
- 每個函式都是物件 && Function的instance
- → 可當作 "值" 指定給其他變數
- callback function
Local function 區域函式
- 定義:函式內部宣告的函式
優點:可 直接存取外部函式的參數 或 先前宣告的區域變數,以減少函數呼叫時要傳遞的引數。
// selectSort.js function sort(nums){ // local functiob function minIndex(left, right){ if (right === nums.length){ return left; } else if (nums[right] < nums[left]){ return minIndex(rigth, right + 1); } else{ return minIndex(left, right + 1); } } // main function for(let i = 0; i < nums.length; ++i){ let selected = minIndex(i, i + 1); if (i !== selected){ // swap i with selected let temp = nums[i]; nums[i] = nums[selected]; nums[selected] = temp; } } }
Callback function 回呼函式
定義:被傳入函式中的函式
// filter1.js function filter(arr, predicate){ let result = []; for (let elem of arr){ if (predicate(elem)){ result.push(elem); } } return result; } // test function lengGreaterThan5(elem){ return elem.length > 5; } function lengLessThan3(elem){ return elem.length < 3; } function (elem){ return elem.includes('a'); } let fruits = ['apple', 'banana', 'cherry']; console.log(filter(arr, lengGreaterThan6)); // ['banana', 'cherry'] console.log(filter(arr, lengLessThen3)); // [] console.log(filter(arr, hasa)); // ['apple', 'banana']
結合local function 和 callback function 範例
// filter2.js function filter(arr, predicate){ let result = []; for (let elem of arr){ if (predicate(elem)){ result.push(elem); } } return result; } function lengGreaterThan(num){ function lengGreaterThanNum(elem){ return elem.length > num; } return lengGreaterThanNum; } let fruits = ['apple', 'banana', 'cherry']; console.log(filter(arr, lengGreaterThan(6))); // ['banana', 'cherry'] console.log(filter(arr, lengGreaterThan(10))); // []
參數預設值
// ex1. ES6以前
function deposit(name, account, amount){
return {
name: name,
account: account,
amount: amount || 1000
};
}
// ex2. ES6
function deposit(name, account, amount=1000){
return {name, account, amount}; // ES6 支援的寫法
}
不定長度引數(ES6)
JS語法允許引數個數比參數多
// ex1. ES6以前: 利用 arguments property function sum(){ var sum = 0; for (var i = 0; i < arguments; ++i){ sum += arguments[i]; } return arguments; } // ex2. ES6 function sum(...numbers){ let total = 0; for (let number of numbers){ total += number; } return total; }
Function
object's propertiesname
length
回傳參數個數(不包含預設參數與不定長度參數)
遞迴
最大公因數範例
// ex1. function declaration function gcd(m, n){ if (n === 0){ return m; } return gcd(n, m % n); } var r1 = gcd(8, 4); if (r1 === 1){ console.log('互質'); } else{ console.log('最大公因數= ' + r); } // ex2. function literal let gcd = function g(n1, n2){ return n2 !== 0 ? g(n2, n1 % n2) : n1; } // ex3. IIFE (function g(n1, n2){ return n2 !== 0 ? g(n2, n1 % n2) : n1; })(8, 4);
Trick: Option object
避免參數太多要一直反覆修正、還容易出現bug的技巧
function ajax(url, option){ let passedOption = { method: option.method || 'GET', contents: option.contents || '', dataType: option.dataType || 'text/plain', // ...以後要新增的參數可陸續加入作為 option object's property }; // option 處理或其他處理 } ajax('www.google.com.tw', { method: 'POST', contents: 'Get JavaScript' });
JS built-in function
ECMAScropt
.sort()
沒有規範JS內建的
.sort()
結果一定是穩定(stable)排序function ascend(n1, n2){ return n1[0] - n2[0]; } function descend(n1, n2){ return n2[0] - n1[0]; } let arr = [[4, 1], [3, 1], [3, 7], [10, 6]]; console.log(arr.sort(ascend)); console.log(arr.sort(descend)); // ascend 結果 [[3, 1], [3, 7], [4, 1], [10, 6]] // 穩定排序 [[3, 7], [3, 1], [4, 1], [10, 6]] // 不穩定排序
- 預設排序方式是根據Unicode碼點,若傳入元素不是字串就會先轉為字串再排序
References