學習軌道
/
JavaScript
JavaScript
/
練習
/
千層麵大師
千層麵大師

千層麵大師

學習練習

簡介

函式是一段有組織、可重複使用的程式碼,用來執行某個動作。 在 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) {
    // ...
  },
};

說明

在這個練習中,你將撰寫更多程式碼,內容與準備和烹調你從最愛食譜書學來的美味千層麵有關。

你有五個任務。 第一個任務與烹調本身有關,另外四個則與完美的準備工作有關。

1. 判斷千層麵是否烤好了

當你把千層麵放進烤箱時,你會想知道是不是已經可以拿出來了。 為了確保千層麵不會在烤箱裡烤焦,你通常會設定計時器。 但有時候你會忘記這件事。

請撰寫一個函式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.'

2. 估算準備時間

為了下一份要準備的千層麵,你想確保自己預留了足夠的時間,好享受烹調的過程。 你已經規劃好千層麵會有哪些層。 現在你想根據這個計畫估算準備工作會花多少時間。

請實作一個函式preparationTime,接受一個層的陣列,以及每層平均的準備時間(以分鐘為單位)。 這個函式應該根據層的數量,回傳總準備時間的估算值。 如果呼叫函式時沒有提供平均準備時間,則應假設為2分鐘。

const layers = ['sauce', 'noodles', 'sauce', 'meat', 'mozzarella', 'noodles'];
preparationTime(layers, 3);
// => 18

preparationTime(layers);
// => 12

3. 計算所需的麵條與醬汁份量

除了預留時間之外,你也想確保自己有足夠的醬汁和麵條,煮出你夢想中的千層麵。 千層麵的每一層麵條,需要 50 公克的麵條。 每一層醬汁則需要 0.2 公升的醬汁。

請定義函式quantities,接受一個層的陣列作為參數。 這個函式會判斷做出這道料理所需的麵條與醬汁份量。 結果應該以帶有noodles和sauce鍵的物件回傳。

quantities(['sauce', 'noodles', 'sauce', 'meat', 'mozzarella', 'noodles']);
// => { noodles: 100, sauce: 0.4 }

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']

5. 依比例調整食譜

你的食譜書上列出的份量只能做出兩人份的千層麵。 因為你下次想煮給更多人吃,所以想算出不同份數所需的份量。

請實作一個函式scaleRecipe,接受兩個參數。

  • 一個食譜物件,內含 2 人份所需的份量。 物件的格式可以參考下面的範例。
  • 你想煮的份數。

這個函式應該回傳一個食譜物件,內含所需份數的份量。 不過,你想保留原本的食譜。 也就是說,在這個任務中,食譜引數不應該被修改。

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,
// };
透過 GitHub 編輯 連結會在新視窗或分頁中開啟
JavaScript Exercism

準備好開始 千層麵大師 了嗎?

註冊 Exercism,透過 37 個概念159 個練習 和真人引導來學習並精通 JavaScript,全部免費。