函式是 JS 的基本。為了讓 JS 幫我們執行一些重複的任務或計算,我們需要把這些程式碼寫成一個函式,依據輸入值的不同,得到不同的結果,進而達到重用的目的。
使用函式前,得先宣告函式,才能呼叫(call)它。
一般函式宣告,長相大概是這樣:
function name(arguments){
// ...
return sth;
}
function
為開頭來宣告()
內可能有零至多個藉由逗號分隔的參數(arguments){}
內為計算的過程、也可以是這個函式要執行的任務undefined
所以今天若要寫一個函式讓它幫我算 x+y,可以這樣寫:
function add(x, y) {
let z = x + y;
return z;
}
console.log(add(3, 4)); // 7
console.log(add(5, 6)); // 11
// 函式的提升
console.log(plus(4, 5)); // 9;雖然呼叫早於宣告,但仍成功呼叫
function plus(x, y) {
let z = x + y;
return z;
}
說明:
使用 add(3,4) 來呼叫,沒有呼叫的話,函式不會執行,前面寫的 function add(x,y)
僅是定義而已。
函式可以重複使用,以範例來說,輸入不同的 x & y 可得到不同結果。
備註:
{ }
宣告的任何變數,無法被外部讀取。同樣的例子也可以寫成函式表達式。它可以是匿名的(沒有函式名稱)、也可以是有函式名稱的。有函式名稱時,可以在函式內代指自己(遞迴,Recursion)。但使用遞迴時,要小心無限迴圈產生過度堆疊(Stack Overflow)的問題;要避免此種情況,需要設定對應條件以避免無限循環。我就這樣第一次把瀏覽器玩壞了XD
常見情況:
// 修改原本範例
let add = function (x, y) {
let z = x + y;
return z;
};
add(3, 4); // 7
add(5, 6); // 11
add(-1, 3); // 2
// 匿名+事件處理,MDN 範例
var myButton = document.querySelector("button");
myButton.onclick = function () {
alert("hello");
};
// 將函式做為參數傳遞給另一函式使用,MDN 範例
function map(f, a) {
const result = new Array(a.length);
for (let i = 0; i < a.length; i++) {
result[i] = f(a[i]);
}
return result;
}
// 遞迴,借用 MDN 範例
function factorial(n) {
if (n == 0 || n == 1) return 1;
else return n * factorial(n - 1);
}
……但我沒用過,說明到此已經是極限了 ((;゚Д゚)
ps. 官方想表達作用域不同的範例 code 無法正常執行,就不放了。
{ }
內定義的所有變數與函式由於這樣的特性,在全域宣告的函式可訪問在全域中的所有變數跟函式;在函式內宣告的子函式,可以訪問父函式內的所有變數與函式、父函式也可訪問所有子函式內的變數與函式。
const x = 100;
let add = function (y) {
let z = x + y;
return z;
};
console.log(add(4)); // 104
console.log(x); // 100
console.log(z); // 讀不到 fn 內的 z;ReferenceError: z is not defined
利用作用域的特性限制變數或函式的存取。
閉包的坑會另開一篇文章來填 ˊ w ˋ
// MDN 的範例
function multiply(a, b = 1) {
return a * b;
}
multiply(5, 2); // 10
multiply(5, 1); // 5
multiply(5); // 5
// 語法,來自 MDN
function f(a, b, ...theArgs) {
// ...
}
...theArgs
會收集剩下的參數(也就是沒被指定名稱的參數),並把這些參數們當作實體陣列。...theArgs
使用陣列的各種方法。以上面的語法示意來說,若傳入了 a, b, c, d, e, f, ... 等參數,c 以後的參數會被 ...theArgs
收容,也可以解開這個陣列(解構賦值,Destructuring assignment)。關於解構賦值,之後會開文章來填坑。
// 範例來自 MDN
function f(...[a, b, c]) {
return a + b + c;
}
f(1); // NaN (b 和 c 都是 undefined)
f(1, 2, 3); // 6
f(1, 2, 3, 4); // 6 (第四個參數不會被解構,因為解構式只有三個定義好的變數名稱)
簡單說,就是把一個函式當參數傳進另一個函式中。
// code from MDN
function greeting(name) {
alert("Hello " + name);
}
function processUserInput(callback) {
let name = prompt("輸入你的名字:");
callback(name);
}
processUserInput(greeting);
宣告時,小括號 ()
內的都叫參數;呼叫時,填進小括號內的都叫引數
function foo(參數) {
// ...
}
foo(引數);
呼,終於寫完了,差點越寫越多寫不完 (☉д⊙)
接下來是陣列與物件的操作~~