轨道
/
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) {
    // ...
  },
};

说明

在这个练习中,你要再写一些代码,用来准备和烹饪你最爱的食谱书里的美味千层面。

你有 5 个任务。 第一个和烹饪本身有关,其余 4 个都和完美的准备工作有关。

1. 判断千层面是否烤好了

千层面在烤箱里的时候,你想知道是不是已经可以把它拿出来了。 为了确保千层面不会在烤箱里烤糊,你通常会设一个定时器。 但有时候你会忘了这回事。

写一个函数 cookingStatus,它接受定时器上剩余的时间(分钟)作为形参。 这个函数有 3 种可能的结果。

  • 如果定时器显示 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. 按份数缩放食谱

你食谱书上列出的用量只够做 2 份千层面。 既然你下次想给更多人做饭,你就想算出不同份数分别需要的用量。

实现一个函数 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,全部免费。