轨道
/
JavaScript
JavaScript
/
练习
/
火车司机
火车司机

火车司机

学习练习

简介

JavaScript 内置了一个...运算符,让处理不定数量的元素变得更简单。根据上下文,它被称为_剩余运算符_或_展开运算符_。

剩余运算符

剩余元素

当...出现在赋值的左侧时,这三个点被称为rest运算符。三个点合上变量名,就叫作剩余元素。它会收集零个或多个值,并把它们存进一个数组里。

const [a, b, ...everythingElse] = [0, 1, 1, 2, 3, 5, 8];
a;
// => 0
b;
// => 1
everythingElse;
// => [1, 2, 3, 5, 8]

注意,和某些其他语言不同,JavaScript 中的rest元素不能有尾随逗号。它_必须_是解构赋值中的最后一个元素。下面的例子会抛出SyntaxError:

const [...items, last] = [2, 4, 8, 16]

剩余属性

和数组类似,剩余运算符也可以用来收集一个或多个对象属性,并把它们存进一个对象里。

const { street, ...address } = {
  street: 'Platz der Republik 1',
  postalCode: '11011',
  city: 'Berlin',
};
street;
// => 'Platz der Republik 1'
address;
// => {postalCode: '11011', city: 'Berlin'}

剩余参数

当...出现在函数定义中最后一个形参旁边时,这个形参被称为_剩余参数_。它让函数能够以数组的形式接收不定数量的实参。

function concat(...strings) {
  return strings.join(' ');
}
concat('one');
// => 'one'
concat('one', 'two', 'three');
// => 'one two three'

展开

展开元素

当...出现在赋值的右侧时,它被称为spread运算符。它会把数组展开成一列元素。和剩余元素不同,它可以出现在数组字面量表达式中的任何位置,而且可以有多个。

const oneToFive = [1, 2, 3, 4, 5];
const oneToTen = [...oneToFive, 6, 7, 8, 9, 10];
oneToTen;
// => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
const woow = ['A', ...oneToFive, 'B', 'C', 'D', 'E', ...oneToFive, 42];
woow;
// =>  ["A", 1, 2, 3, 4, 5, "B", "C", "D", "E", 1, 2, 3, 4, 5, 42]

展开属性

和数组类似,展开运算符也可以用来把一个对象的属性复制到另一个对象里。

let address = {
  postalCode: '11011',
  city: 'Berlin',
};
address = { ...address, country: 'Germany' };
// => {
//   postalCode: '11011',
//   city: 'Berlin',
//   country: 'Germany',
// }

说明

你的朋友 Linus 是一名火车司机,驾驶货运列车往返于各个城市之间。 虽然他们很擅长开火车,却不太擅长处理物流或电脑方面的事情。 他们想请你用编程帮忙整理列车信息,并修正路线数据中的错误。

Note

为了练习,请使用 rest 或 spread 运算符来解决下面的每个任务。

1. 创建所有车厢的数组

你的朋友一直在记录每节车厢的标识符(ID),但始终不确定系统在某一时刻需要处理多少节车厢。 如果把这些数据打包成一个统一的array,物流程序的其余部分处理起来会容易得多。

实现一个函数 getListOfWagons,它接受任意数量的车厢 ID,这些 ID 就是每节车厢的标识。 每个 ID 都是一个正整数。 函数应把这些 ID 作为单个array返回。

getListOfWagons(1, 7, 12, 3, 14, 8, 5);
// => [1, 7, 12, 3, 14, 8, 5]

2. 把前两个元素移到数组末尾

到这里,你对这些数据以及它在物流程序中的用法开始有所体会。 ID 系统总是给火车头分配 ID 1,列车中其余的车厢则被随机分配一个大于 1 的 ID。

你的朋友需要给列车挂上两节新车厢,却忘了更新系统! 现在,列车array中的前两节车厢必须移到末尾,否则整个顺序都会乱掉。

如果你能帮 Linus 修正这些错误,他们会非常感激。

实现一个函数 fixListOfWagons,它接受一个数组,里面是每节车厢的 id。 它return一个array,其中前两个元素被移到array的末尾,这样火车头就能排在最前面。

eachWagonsID = [2, 5, 1, 7, 4, 12, 6, 3, 13];
fixListOfWagons(eachWagonsID);
// => [1, 7, 4,  12, 6, 3, 13, 2, 5]

3. 添加缺失的值

糟糕,有些车厢好像不见了。

幸运的是,你的朋友刚找到了另一个array,里面似乎装着缺失的车厢 ID,想请你把它们加到主车厢 ID array中。 他们唯一记得的是,缺失的值应该直接放在指定火车头的后面。

根据这个新信息,写一个名为 correctListOfWagons 的函数,它接收两个数组作为实参,这两个数组包含每节车厢的 ID。 第二个array中的车厢 ID 应该加到第一个array中,紧跟在火车头(ID 1)之后。

eachWagonsID = [1, 5, 20, 7, 4, 8];
missingWagons = [3, 17, 6, 15];
correctListOfWagons(eachWagonsID, missingWagons);
// => [1, 3, 17, 6, 15, 5, 20, 7, 4, 8]

4. 扩展路线信息

现在所有车厢数据都正确了,你的朋友想请你更新系统的路线信息。 最初的路线信息已经构造成一个object,你的朋友想请你用提供的补充内容来更新它。 每条路线需要的信息都略有不同,所以你的朋友很希望有一个通用的解决方案。

实现一个函数 extendRouteInformation,它接受两个object。 第一个object包含列车路线往返于哪些城市之间。

第二个object包含其他路线细节,比如列车的速度或长度。 函数应返回一个包含所有路线信息的合并objects。

Note

变量 moreRouteInformation 可以包含不同的属性。

route = { from: 'Berlin', to: 'Hamburg' };
moreRouteInformation = { length: '100', speed: '50' };
extendRouteInformation(route, moreRouteInformation);
// => {from: "Berlin", to: "Hamburg", length: "100", speed: "50"}

5. 把到达时间从路线信息中分离出来

你的朋友注意到,路线信息里并不需要到达时间。 所以他们想请你把到达时间从路线信息中分离出来。

实现一个函数 separateTimeOfArrival,它接受一个包含路线信息的对象。 函数应返回一个数组,数组的第一个元素是到达时间,第二个元素是一个对象,里面包含不含到达时间的路线信息。

routeInformation = {
  from: 'Berlin',
  to: 'Hamburg',
  length: '100',
  timeOfArrival: '10:10',
};
separateTimeOfArrival(routeInformation);
// => ["10:10", {from: "Berlin", to: "Hamburg", length: "100"}]
通过 GitHub 编辑 链接将在新窗口或新标签页中打开
JavaScript Exercism

准备好开始 火车司机 了吗?

注册 Exercism,借助 37 个概念159 个练习 和真人导师指导,学习并掌握 JavaScript,全部免费。