- Introduction
- Chapter 1 Values, Types, and Operators
- Chapter 2 Program Structure
- Expressions and statements
- Variables
- Keywords and reserved words
- The environment
- Functions
- The console.log function
- Return values
- prompt and confirm
- Control flow
- Conditional execution
- while and do loops
- Indenting Code
- for loops
- Breaking Out of a Loop
- Updating variables succinctly
- Dispatching on a value with switch
- Capitalization
- Comments
- Summary
- Exercises
- Chapter 3 Functions
- Chapter 4 Data Structures: Objects and Arrays
- Chapter 5 Higher-Order Functions
- Chapter 6 The Secret Life of Objects
- Chapter 7 Project: Electronic Life
- Chapter 8 Bugs and Error Handling
- Chapter 9 Regular Expressions
- Creating a regular expression
- Testing for matches
- Matching a set of characters
- Repeating parts of a pattern
- Grouping subexpressions
- Matches and groups
- The date type
- Word and string boundaries
- Choice patterns
- The mechanics of matching
- Backtracking
- The replace method
- Greed
- Dynamically creating RegExp objects
- The search method
- The lastIndex property
- Parsing an INI file
- International characters
- Summary
- Exercises
- Chapter 10 Modules
- Chapter 11 Project: A Programming Language
- Chapter 12 JavaScript and the Browser
- Chapter 13 The Document Object Model
- Chapter 14 Handling Events
- Chapter 15 Project: A Platform Game
- Chapter 16 Drawing on Canvas
- Chapter 17 HTTP
- Chapter 18 Forms and Form Fields
- Chapter 19 Project: A Paint Program
- Chapter 20 Node.js
- Chapter 21 Project: Skill-Sharing Website
- Eloquent JavaScript
- Exercise Hints
- Program Structure
- Functions
- Data Structures: Objects and Arrays
- Higher-Order Functions
- The Secret Life of Objects
- Project: Electronic Life
- Bugs and Error Handling
- Regular Expressions
- Modules
- Project: A Programming Language
- The Document Object Model
- Handling Events
- Project: A Platform Game
- Drawing on Canvas
- HTTP
- Forms and Form Fields
- Project: A Paint Program
- Node.js
- Project: Skill-Sharing Website
Animating life
The next step is to write a turn
method for the world object that gives the critters a chance to act. It will go over the grid using the forEach
method we just defined, looking for objects with an act
method. When it finds one, turn
calls that method to get an action object and carries out the action when it is valid. For now, only "move"
actions are understood.
There is one potential problem with this approach. Can you spot it? If we let critters move as we come across them, they may move to a square that we haven’t looked at yet, and we’ll allow them to move again when we reach that square. Thus, we have to keep an array of critters that have already had their turn and ignore them when we see them again.
World.prototype.turn = function() { var acted = []; this.grid.forEach(function(critter, vector) { if (critter.act && acted.indexOf(critter) == -1) { acted.push(critter); this.letAct(critter, vector); } }, this); };
We use the second parameter to the grid’s forEach
method to be able to access the correct this
inside the inner function. The letAct
method contains the actual logic that allows the critters to move.
World.prototype.letAct = function(critter, vector) { var action = critter.act(new View(this, vector)); if (action && action.type == "move") { var dest = this.checkDestination(action, vector); if (dest && this.grid.get(dest) == null) { this.grid.set(vector, null); this.grid.set(dest, critter); } } }; World.prototype.checkDestination = function(action, vector) { if (directions.hasOwnProperty(action.direction)) { var dest = vector.plus(directions[action.direction]); if (this.grid.isInside(dest)) return dest; } };
First, we simply ask the critter to act, passing it a view object that knows about the world and the critter’s current position in that world (we’ll define View
in a moment ). The act
method returns an action of some kind.
If the action’s type
is not "move"
, it is ignored. If it is "move"
, if it has a direction
property that refers to a valid direction, and if the square in that direction is empty (null), we set the square where the critter used to be to hold null and store the critter in the destination square.
Note that letAct
takes care to ignore nonsense input—it doesn’t assume that the action’s direction
property is valid or that the type
property makes sense. This kind of defensive programming makes sense in some situations. The main reason for doing it is to validate inputs coming from sources you don’t control (such as user or file input), but it can also be useful to isolate subsystems from each other. In this case, the intention is that the critters themselves can be programmed sloppily—they don’t have to verify if their intended actions make sense. They can just request an action, and the world will figure out whether to allow it.
These two methods are not part of the external interface of a World
object. They are an internal detail. Some languages provide ways to explicitly declare certain methods and properties private and signal an error when you try to use them from outside the object. JavaScript does not, so you will have to rely on some other form of communication to describe what is part of an object’s interface. Sometimes it can help to use a naming scheme to distinguish between external and internal properties, for example by prefixing all internal ones with an underscore character (_). This will make accidental uses of properties that are not part of an object’s interface easier to spot.
The one missing part, the View
type, looks like this:
function View(world, vector) { this.world = world; this.vector = vector; } View.prototype.look = function(dir) { var target = this.vector.plus(directions[dir]); if (this.world.grid.isInside(target)) return charFromElement(this.world.grid.get(target)); else return "#"; }; View.prototype.findAll = function(ch) { var found = []; for (var dir in directions) if (this.look(dir) == ch) found.push(dir); return found; }; View.prototype.find = function(ch) { var found = this.findAll(ch); if (found.length == 0) return null; return randomElement(found); };
The look
method figures out the coordinates that we are trying to look at and, if they are inside the grid, finds the character corresponding to the element that sits there. For coordinates outside the grid, look
simply pretends that there is a wall there so that if you define a world that isn’t walled in, the critters still won’t be tempted to try to walk off the edges.
This is a book about getting computers to do what you want them to do. Computers are about as common as screwdrivers today, but they contain a lot more hidden complexity and thus are harder to operate and understand. To many, they remain alien, slightly threatening things.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论