Reliable JavaScript. Lawrence Spencer
Чтение книги онлайн.
Читать онлайн книгу Reliable JavaScript - Lawrence Spencer страница 6
This section is about hitting the right keys at the right time. As you might guess, there’s more to it than the uninitiated might think.
But first, a story.
Mastering the Features of JavaScript
Have you ever seen someone get his head chopped off on a squash court? One of us nearly did. It was during an introductory college course in the sport, but the episode had a lot to teach about writing reliable JavaScript.
In case you’re not familiar with the game, it’s played in a court that is like a large room. Two players alternate hitting a ball with their rackets toward the back wall, which they both face. In the most basic scenario, you hit the ball at the wall; it bounces off and then bounces off the floor toward your opponent, who is standing next to you. Then he smashes it toward the back wall for you to try to hit.
Anyway, it was the first day of the course. The instructor was standing to the student’s left and a little behind him, and the rest of us were watching through the glass front wall. The instructor directed the student to hit the ball toward the back wall.
The student, who was a tennis player, hit a forehand as he would in tennis, stroking from low to high, with a high follow-through that wrapped around his body. That is how you hit with topspin in tennis. It’s also how you chop off the head of whoever happens to be standing to your left and a little behind you.
Fortunately, the instructor knew this would happen and had positioned his racket in front of his face to defend himself.
The student’s racket crashed against the instructor’s, making a lot of noise and causing the student some embarrassment, but no harm was done.
The instructor pointed out that in tennis, you generally hit with topspin so the ball dives down and bounces up with a kick toward your opponent. However, that same stroke in squash does the opposite. If you hit with topspin, the squash ball will kick up off the wall, making an easy, looping arc, and then bounce in a lazy manner off the floor, whence your opponent will crush it. In squash, you want to hit with backspin. The ball will then kick down off the wall, and kick off the floor toward your opponent with increased velocity.
The normal stroke in squash, then, is a chopping, downward motion to impart backspin – just the opposite of the typical stroke in tennis.
Even though the two sports have basic features in common (two players, rackets, and a ball) as well as common demands (good hand-eye coordination, good anticipation and movement on your feet), you won’t play squash well if you try to hit the ball as you would in tennis.
In the same way, JavaScript makes its particular demands on the programmer. If you come to large-scale JavaScript development with primary experience in another language, you will do well to attune yourself to the differences in technique.
The differences are at both the small scale of syntax and the large scale of architecture and engineering.
Throughout this book, you will encounter JavaScript’s unique syntactic delights. Many of them are summarized in Chapter 25. This chapter looks at the larger issues of how JavaScript’s peculiarities make certain engineering techniques possible.
By employing these techniques, you will write JavaScript with kick. Your game will improve. You will “win” more often because you will be working with the language instead of contrary to it.
Case Study: D3.js
Mike Bostock’s JavaScript masterpiece, D3.js
, is a perfect example.
D3 stands for Data-Driven Documents, so called because it lets you create beautiful SVG graphics from data. For example, Figure 1.1 is a D3 diagram that shows class dependencies in a software system (from http://bl.ocks.org/mbostock/4341134).
Figure 1.2 presents the same data in a radial layout (http://bl.ocks.org/mbostock/1044242). D3 is very flexible. It is also very concise; each diagram takes just a few dozen lines of pleasingly formatted JavaScript to create.
D3’s home page is http://d3js.org, with source code available at https://github.com/mbostock/d3. This is real JavaScript, not for the faint of heart and orders of magnitude more artful than the field-validators and button-handlers that are sprinkled through a typical website.
In fact, it’s so artful as to be overwhelming at first read, so we have simplified just one corner of it for discussion. Listing 1-1 is an abridged version of d3.svg.line
, a function that creates an SVG line generator. An explanation follows the listing.
LISTING 1-1: A function to create an SVG line (code filename: rj3\rj3.js)
You would use this function to turn an array of data into an SVG path. SVG paths are just strings in the small language of SVG. Suppose you wanted to draw a line like the one in Figure 1.3.
The SVG <path>
element would be
In English, that says to pick up the pen and move it (“M”) to the (x, y) coordinate (10, 130), and then draw a line (“L”) to (100, 60), and then draw another line to (190, 160), and then finish with a line to (280, 10).
So how does the code in Listing 1-1 create a path like that? Consider Listing 1-2, which contains a sample call.
LISTING 1-2: Sample call to rj3.svg.line() (code filename: rj3\pathFromArrays.js)
On the highlighted line, what ends up in lineGenerator? Well, according to the last line of Listing 1-1, a call to rj3.svg.line()
will return something called line
. What is that? It is a function nested inside the outer function rj3.svg.line
!
NOTE In JavaScript, functions can nest inside other functions. This becomes an important way to control scope.
By the way, we have retained D3’s names for most properties and variables so you can study the full listing at https://github.com/mbostock/d3/blob/master/src/svg/line.js if you wish, and be as well-oriented to it as possible. In only a few cases have we attempted to clarify things by changing a variable’s name. If you find it confusing that both the outer and inner functions are named line
, well, this is very much in the spirit of all the D3 source code so you might as well learn to enjoy it.
Yes, the function returns a function. This is a confusing no-no in most languages, but in JavaScript it’s a very idiomatic yes-yes that broadens your architectural