函式是一段有組織、可重複使用的程式碼,用來執行某個動作。 在 JavaScript 中,定義函式的方式有很多種。 這裡我們會看_函式宣告_和_函式運算式_。 其他做法,例如箭頭函式,會在其他概念中介紹。
在 JavaScript 中,定義函式的標準方式是_函式宣告_,也稱為_函式定義_或_函式敘述_。
它由function關鍵字、函式名稱,以及放在括號中、以逗號分隔的參數清單組成。
接著是由大括號包住的函式主體(一組定義函式做些什麼的敘述)。
function someName(param1, param2, param3) {
// ...
}
在 JavaScript 中,呼叫函式的方式,就是寫出函式名稱,後面接著一對包含引數的括號。
someName(arg1, arg2, arg3);
在函式主體內使用參數時,要注意可能出現的副作用。
在 JavaScript 中,函式宣告裡定義的所有參數預設都是選用的。
如果你提供的引數比參數少,缺少的引數在函式內會是undefined,請參閱null與undefined。
在很多情況下,指定一個比undefined更合適的預設值會更合理。
做法是在函式定義中直接指定預設參數。
function someName(param1 = defaultValue1, param2 = defaultValue2) {
// ...
}
return敘述return敘述會結束函式的執行,並指定一個回傳給函式呼叫者的值。一個函式可以有多個return敘述。
function checkNumber(num) {
if (num === 0) {
return 'You passed 0, please provide another number.';
}
return 'Thanks for passing such a nice number.';
}
函式的回傳值可以存到變數裡。
function sum(x, y) {
return x + y;
}
const total = sum(5, 10);
// => 15
一個沒有return任何值、或沒有return敘述的函式,其結果是undefined。
JavaScript 沒有隱式的return。
function nakedReturn(a) {
a * 2;
return;
}
nakedReturn(1);
// => undefined
function noReturn(a) {
a * 2;
}
noReturn(1);
// => undefined
在 JavaScript 中,你只能回傳恰好一個值。 如果你想傳遞更多資訊,必須先把它們合併成單一實體,通常是物件或陣列。
function divide(a, b) {
return {
quotient: Math.floor(a / b),
remainder: a % b,
};
}
函式宣告是一個獨立的敘述。 但有時候,把函式定義成另一個運算式的一部分會很方便,例如在指定中、當作函式參數(回呼函式),或在物件中當作值。 這可以用函式運算式來做到。 它的語法和函式宣告相同,差別在於可以省略函式名稱,建立一個_匿名函式_。
const someFunction = function (param) {
// ...
};
someOtherFunction(function (param) {
// ...
});
const obj = {
someFunction: function (param) {
// ...
},
};
在這個練習中,你將撰寫更多程式碼,內容與準備和烹調你從最愛食譜書學來的美味千層麵有關。
你有五個任務。 第一個任務與烹調本身有關,另外四個則與完美的準備工作有關。
當你把千層麵放進烤箱時,你會想知道是不是已經可以拿出來了。 為了確保千層麵不會在烤箱裡烤焦,你通常會設定計時器。 但有時候你會忘記這件事。
請撰寫一個函式cookingStatus,接受計時器剩餘的分鐘數作為參數。
這個函式有三種可能的結果。
0,應該回傳'Lasagna is done.'。'Not done, please wait.'。'You forgot to set the timer.'。計時器永遠不會顯示低於 0 的數值。
cookingStatus(12);
// => 'Not done, please wait.'
cookingStatus();
// => 'You forgot to set the timer.'
為了下一份要準備的千層麵,你想確保自己預留了足夠的時間,好享受烹調的過程。 你已經規劃好千層麵會有哪些層。 現在你想根據這個計畫估算準備工作會花多少時間。
請實作一個函式preparationTime,接受一個層的陣列,以及每層平均的準備時間(以分鐘為單位)。
這個函式應該根據層的數量,回傳總準備時間的估算值。
如果呼叫函式時沒有提供平均準備時間,則應假設為2分鐘。
const layers = ['sauce', 'noodles', 'sauce', 'meat', 'mozzarella', 'noodles'];
preparationTime(layers, 3);
// => 18
preparationTime(layers);
// => 12
除了預留時間之外,你也想確保自己有足夠的醬汁和麵條,煮出你夢想中的千層麵。 千層麵的每一層麵條,需要 50 公克的麵條。 每一層醬汁則需要 0.2 公升的醬汁。
請定義函式quantities,接受一個層的陣列作為參數。
這個函式會判斷做出這道料理所需的麵條與醬汁份量。
結果應該以帶有noodles和sauce鍵的物件回傳。
quantities(['sauce', 'noodles', 'sauce', 'meat', 'mozzarella', 'noodles']);
// => { noodles: 100, sauce: 0.4 }
不久前你拜訪了一位朋友,並在那裡吃了千層麵。 那真是美味極了,而且有些特別之處。 朋友寄給你食材清單,並告訴你清單上的最後一項就是讓那道料理如此特別的「祕密食材」。 現在你也想把那個祕密食材加進自己的食譜裡。
請撰寫一個函式addSecretIngredient,接受兩個食材陣列作為參數。
第一個參數是朋友寄給你的清單,第二個則是你自己食譜的食材清單。
這個函式應該把朋友清單上的最後一項加到你的清單末端。
代表你食譜的陣列應該直接被修改,而函式不應該回傳任何東西。
不過,第一個引數不應該被修改。
const friendsList = ['noodles', 'sauce', 'mozzarella', 'kampot pepper'];
const myList = ['noodles', 'meat', 'sauce', 'mozzarella'];
addSecretIngredient(friendsList, myList);
// => undefined
console.log(myList);
// => ['noodles', 'meat', 'sauce', 'mozzarella', 'kampot pepper']
你的食譜書上列出的份量只能做出兩人份的千層麵。 因為你下次想煮給更多人吃,所以想算出不同份數所需的份量。
請實作一個函式scaleRecipe,接受兩個參數。
這個函式應該回傳一個食譜物件,內含所需份數的份量。 不過,你想保留原本的食譜。 也就是說,在這個任務中,食譜引數不應該被修改。
const recipe = {
noodles: 200,
sauce: 0.5,
mozzarella: 1,
meat: 100,
};
scaleRecipe(recipe, 4);
// =>
// {
// noodles: 400,
// sauce: 1,
// mozzarella: 2,
// meat: 200,
// };
console.log(recipe);
// =>
// {
// noodles: 200,
// sauce: 0.5,
// mozzarella: 1,
// meat: 100,
// };