1
0
mirror of https://github.com/apachecn/eloquent-js-3e-zh.git synced 2025-05-23 20:02:20 +00:00
This commit is contained in:
wizardforcel 2018-05-05 10:35:45 +08:00
parent 64453c884e
commit ccf4b74ed0

38
7.md
View File

@ -6,13 +6,13 @@
<figure class="chapter framed">![Picture of a package-delivery robot](img/chapter_picture_7.jpg)</figure>
In “project” chapters, Ill stop pummeling you with new theory for a brief moment and instead well work through a program together. Theory is necessary to learn to program, but reading and understanding actual programs is just as important.
在“项目”章节中,我会在短时间内停止向你讲述新理论,相反我们会一起完成一个项目。 学习编程理论是必要的,但阅读和理解实际的计划同样重要。
Our project in this chapter is to build an automaton, a little program that performs a task in a virtual world. Our automaton will be a mail-delivery robot picking up and dropping off parcels.
我们在本章中的项目是构建一个自动机,一个在虚拟世界中执行任务的小程序。 我们的自动机将是一个接送包裹的邮件递送机器人。
## Meadowfield
The village of Meadowfield isnt very big. It consists of 11 places with 14 roads between them. It can be described with this array of roads:
Meadowfield 村不是很大。 它由 11 个地点和 14 条道路组成。 它可以用`roads`数组来描述:
```
const roads = [
@ -26,11 +26,11 @@ const roads = [
];
```
<figure>![The village of Meadowfield](img/village2x.png)</figure>
![The village of Meadowfield](img/village2x.png)
The network of roads in the village forms a _graph_. A graph is a collection of points (places in the village) with lines between them (roads). This graph will be the world that our robot moves through.
村里的道路网络形成了一个图。 图是节点(村里的地点)与他们之间的边(道路)的集合。 这张图将成为我们的机器人在其中移动的世界。
The array of strings isnt very easy to work with. What were interested in is the destinations that we can reach from a given place. Lets convert the list of roads to a data structure that, for each place, tells us what can be reached from there.
字符串数组并不易于处理。 我们感兴趣的是,我们可以从特定地点到达的目的地。 让我们将道路列表转换为一个数据结构,对于每个地点,都会告诉我们从那里可以到达哪些地点。
```
function buildGraph(edges) {
@ -52,27 +52,27 @@ function buildGraph(edges) {
const roadGraph = buildGraph(roads);
```
Given an array of edges, `buildGraph` creates a map object that, for each node, stores an array of connected nodes.
给定边的数组,`buildGraph`创建一个映射对象,该对象为每个节点存储连通节点的数组。
It uses the `split` method to go from the road strings, which have the form `"Start-End"`, to two-element arrays containing the start and end as separate strings.
它使用`split`方法,将形式为`"Start-End"`的道路字符串,转换为两元素数组,包含起点和终点作为单个字符串。
## The task
## 任务
Our robot will be moving around the village. There are parcels in various places, each addressed to some other place. The robot picks up parcels when it comes to them and delivers them when it arrives at their destinations.
我们的机器人将在村庄周围移动。 在各个地方都有包裹,每个都寄往其他地方。 机器人在收到包裹时拾取包裹,并在抵达目的地时将其送达。
The automaton must decide, at each point, where to go next. It has finished its task when all parcels have been delivered.
自动机必须在每个点决定下一步要去哪里。 所有包裹递送完成后,它就完成了任务。
To be able to simulate this process, we must define a virtual world that can describe it. This model tells us where the robot is and where the parcels are. When the robot has decided to move somewhere, we need to update the model to reflect the new situation.
为了能够模拟这个过程,我们必须定义一个可以描述它的虚拟世界。 这个模型告诉我们机器人在哪里以及包裹在哪里。 当机器人决定移到某处时,我们需要更新模型以反映新情况。
If youre thinking in terms of object-oriented programming, your first impulse might be to start defining objects for the various elements in the world. A class for the robot, one for a parcel, maybe one for places. These could then hold properties that describe their current state, such as the pile of parcels at a location, which we could change when updating the world.
如果你正在考虑面向对象编程,你的第一个冲动可能是开始为世界中的各种元素定义对象。 一个机器人,一个包裹,也许还有一个地点。 然后,它们可以持有描述其当前状态的属性,例如某个位置的一堆包裹,我们可以在更新世界时改变这些属性。
This is wrong.
这是错的。
At least, it usually is. The fact that something sounds like an object does not automatically mean that it should be an object in your program. Reflexively writing classes for every concept in your application tends to leave you with a collection of interconnected objects that each have their own internal, changing state. Such programs are often hard to understand and thus easy to break.
至少,通常是这样。 一个东西听起来像一个对象,并不意味着它应该是你的程序中的一个对象。 为应用程序中的每个概念反射式编写类,往往会留下一系列互连对象,每个对象都有自己的内部的变化的状态。 这样的程序通常很难理解,因此很容易崩溃。
Instead, lets condense the villages state down to the minimal set of values that define it. Theres the robots current location and the collection of undelivered parcels, each of which has a current location and a destination address. Thats it.
相反,让我们将村庄的状态压缩成定义它的值的最小集合。 机器人的当前位置和未送达的包裹集合,其中每个都拥有当前位置和目标地址。这样就够了。
And while were at it, lets make it so that we dont _change_ this state when the robot moves, but rather compute a _new_ state for the situation after the move.
当我们到达新地点时,让我们这样做,在机器人移动时不会改变这种状态,而是在移动之后为当前情况计算一个新状态。
```
class VillageState {
@ -95,9 +95,9 @@ class VillageState {
}
```
The `move` method is where the action happens. It first checks whether there is a road going from the current place to the destination, and if not, it returns the old state, since this is not a valid move.
`move`方法是动作发生的地方。 它首先检查是否有当前位置到目的地的道路,如果没有,则返回旧状态,因为这不是有效的移动。
Then it creates a new state with the destination as the robots new place. But it also needs to create a new set of parcels—parcels that the robot is carrying (that are at the robots current place) need to be moved along to the new place. And parcels that are addressed to the new place need to be delivered—that is, they need to be removed from the set of undelivered parcels. The call to `map` takes care of the moving, and the call to `filter` does the delivering.
然后它创建一个新的状态,将目的地作为机器人的新地点。 但它也需要创建一套新的包裹 - 机器人携带的包裹(位于机器人当前位置)需要移动到新位置。 而要寄往新地点的包裹需要送达 - 也就是说,需要将它们从未送达的包裹中移除。 `'map'`的调用处理移动,并且`'filter'`的调用处理递送。
Parcel objects arent changed when they are moved, but recreated. The `move` method gives us a new village state, but leaves the old one entirely intact.