JavaScript in a Jiffy

by Brian Hayes

The world’s computers run more programs written in JavaScript than in any other language. The reason for this huge popularity is not any special virtue of the language itself. The big reason for writing in JavaScript is that you can publish your work on the Web, and anyone with a browser can run your program without having to download or install anything. If you are writing a story that’s going to be read online, JavaScript allows you to go beyond words and pictures, creating animated or interactive elements that are instantly available to your readers.

These computational aids to storytelling open up a whole new channel of communication, a new way of presenting data or explaining ideas. They are especially useful in science writing, where we often have intellectually challenging material to get across. Consider the U.S. Health Map, which distills data on more than 3,000 U.S. counties into a form that allows you to step back and see overall patterns or drill down for the details. Or take the JavaScript Black Hole, which vividly illustrates the concept of gravitational lensing in astronomy.

The Resources page of this website lists several other impressive works in JavaScript (look under the headings Dava Viz and Simulations and Interactive Presentations). Most of those illustrations were created by virtuoso programmers with long experience and deep expertise. A one-day workshop will not bring you up to that level. But it is entirely possible for an amateur to construct engaging and useful web “interactives” that help explain ideas in the sciences. Here’s one of mine:

Click the Run button. The lacy, fernlike patterns are created by an algorithm called diffusion-limited aggregation, which models many natural processes, from sedimentation on the seafloor to the growth of tumors and bacterial colonies. What you are seeing is not a movie—it’s not an event recorded once and then replayed the same way forever after. Every time you click the button, the simulation runs anew, computing a new pattern. (A version of the program with extra knobs and switches, allowing you to explore and experiment, is available here.)

In this tutorial we’re going to explore and experiment with JavaScript itself. You’ll be able to write code directly in this web page, and then run your program to see the results. Before we get started, there are a few preliminaries.

The JavaScript Playground

This is what JavaScript looks like in its native habitat:

You may not fully understand the program above, but you can play with it anyway. Go ahead and press the Run button and you’ll see the program’s output in a new panel. Try editing the code, and then run it again to see the effect of your changes. For example, in line 18 you might change i <= 20 to i <= 50 to see some larger Fibonacci numbers. Or make line 9 read var a = 2, b = 1, tmp; to generate a slightly less famous sequence known as the Lucas numbers. Another experiment worth trying: Change line 15 to return b / a;. Or just go wild—modify the code in anyway you want, or replace if with your own program. If you ever want to get back to the original state of the code, that’s what the Reset button is for.

The ratio of successive Fibonacci numbers converges to a number called phi, also known as the golden ratio. The numerical value is about 1.618. If you’re into this sort of thing, you might want to try the experiment and see what value the ratio of successive Lucas numbers converges to.

What if you make a mistake? It won’t be the first time a computer program has had a bug in it. With some kinds of errors, the program will run but give a wrong answer. More likely, it won’t run at all, and you’ll see an error message if you open up the console. The most annoying goofs are those that cause the program to run forever—to enter an infinite loop. If you’re lucky, the browser will complain about a script that’s taking too long and offer you an opportunity to stop it. Otherwise, you may have to close the tab or window, or even shut down your browser.

One more thing before moving on. Notice in line 20 the phrase console.log( ... );. This command is how we direct output to the JavaScript console (and, in this tutorial, to an output panel). In a finished program, console.log() commands almost never appear, but they are a useful way of peeking inside the program during development and testing. They provide the communications channel we need to have a dialogue with JavaScript.

Give it a try in the editor panel below. I have filled in the tired old greeting that has been a cliché of programming language manuals for almost 40 years. Improve on it! Personalize it. Add some more console.log() statements of your own. Try putting other kinds of values in the parentheses—maybe an arithmetic expression such as 6 * 7. Again, press the Run button and make sure the result is what you expected to see.

Functions

Where to start in learning a language? Do you memorize a bunch of words and rules, or just plunge into conversation? I favor the latter strategy, and so I am going to start with fully formed sentences rather than individual words. We’ll worry about spelling and punctuation later.

Functions are the basic units of discourse in JavaScript, roughly analogous to sentences or paragraphs of English prose. Here are a few one-liners. You can probably guess what they do, but run the code anyway.

Lines 1, 3, and 5 are function definitions. They create the function—in effect, teaching JavaScript a new trick—but they don’t actually compute anything. The computing happens when you call (or invoke or execute) the function. Each of the console.log() statements in lines 7 through 10 calls one of the functions we have just defined.

A function definition has four parts:

To call a function, just write its name followed by a pair of parentheses enclosing the values that will become inputs (or arguments) to the function. For example, consider the function square, which is defined above with the parameter list (n) and the body { return n * n }. Invoking this function as square(12) gives the parameter n a value of 12, and so the computation done in the body of the function is 12 × 12 = 144. Calling square(15), on the other hand, returns 225.

Some functions are associated with or belong to a particular object in the JavaScript system. They are known as methods, and there is a special “dotted” syntax for calling them. We have already met two such methods. In console.log(), the log() function is a method of the console object. Similarly in Math.random(), the random() function is a method of an object named Math. Math.random() returns a random number between 0 and 1.

Exercise: Write a function celsius that does the inverse of fahrenheit. You can insert the definition anywhere you wish in the panel above, then write a console.log() statement that tests your function for the Fahrenheit values 32 and 212. (If you’re stuck, here’s my answer.)

function celsius(fahrenheit) { return (fahrenheit - 32) * (100 / 180); }

Back to Basics

It’s time to build up some vocabulary and learn the minutiae of spelling, grammar, and puctuation.

The simplest elements of JavaScript are numbers, text strings, and boolean truth values.

Named for the 19th-century logician George Boole.

This is a good place to mention a few other niggling details. These rules are JavaScript analogues of “i before e except after c.”

Doing Things with Numbers and Strings

Arithmetic in JavaScript is quite conventional. The symbols +, -, *, / denote the four familiar operations that Lewis Carroll called ambition, distraction, uglification and derision. There’s also %, which calculates not percentage but remainder after division: 5 % 2 == 1. Other numerical operations live in the Math object (the capital letter is important). For example, Math.floor(n) returns the integer part of n, and Math.pow(x, y) returns x raised to the yth power.

Text strings have their own set of operations, most of them implemented as methods belonging to the strings themselves. In the first line below, we create a string and assign it to the variable s. (More on variables and assignments in just a bit.) Then we invoke four of the methods of the string object s. Before running the code, you might record as a comment following the double slash on each line the value that you expect the expression to return.

Observe that s.split(" ") splits the string at every instance of the space character, " ". What do you suppose s.split("") would return, where the argument is not a space character but an empty string? There’s an easy way to find out.

The joker among all these numeric and alphabetic operations is the plus sign, which works on both numbers and text strings but in different ways. There’s not much mystery in an expression such as 50 + 7; it yields a value of 57. In JavaScript, + also acts on strings, performing not addition but concatenation. (Carroll might have called this one concussion.) Thus "fifty" + "seven" returns a value of "fiftyseven". What about "50" + "7"? Well, the two operands are not numbers but strings, so they get concatenated rather than added; the value is "507". The trickiest case is 50 + "7", where one operand is a number and the other a string. Whatever will happen to them? Try the experiment!

Arrays and Objects

Numbers, booleans, and strings are the atoms and molecules of computational matter. They are building blocks from which you can make higher-level structures. The two main composite structures are called arrays and objects.

An array is written as a list of items separated by commas and enclosed in square brackets:

As these example show, the items in an array can be numbers or text strings or other data elements, and a single array can hold elements of diverse types. And there’s nothing wrong with an empty array, or with arrays of arrays.

An array is an ordered collection of items. This is essential to its nature: the items are numbered, counting up from 0. Storing items, retrieving them, or modifying them—it’s all done by the numbers. In the panel below we define two arrays, called nouns and verbs, each with seven elements. Then we can access any element of the arrays with the notation nouns[i] or verbs[i], where the index i is an integer between 0 and 6. The console.log() statement on line 6 selects three items to construct a rudimentary English sentence.

Try modifying the console.log() statement to generate a different sentence. Or insert a statement such as verbs[6] = "sniffed" on line 5 to replace one of the words. Feeling adventurous? In selecting an array element, the expression inside the square brackets doesn’t have to be a plain number; it could be any expression that yields a number in the appropriate range, such as verbs[1 + 4]. The JavaScript fragment Math.floor(Math.random() * 7) returns a random integer between 0 and 6. Can you use this expression to generate some random nonsense about Big Papi, spaghetti, and so on? (Hint.)

The brute-force method is to copy the expression Math.floor(Math.random() * 7) three times, putting it into each of the array references. A better idea is to define a function—maybe call it random7()—with the statement return Math.floor(Math.random() * 7) in the body. Then make the final line of the program read: console.log(nouns[random7()], verbs[random7()], nouns[random7()]);

Arrays have still more tricks. For example, every array comes with a built-in method for reversing the order of its elements, and another for sorting them.

Whereas arrays let you put items in numerical order, objects organize things by naming them. A name, or key, is a text string or anything that JavaScript can turn into a string. Each key is associated with a value, which can be pretty much anything—a string, a number, an array, another object. In written form, an object is a list of key:value pairs separated by commas and enclosed in curly braces, like so:

All the keys in an object are treated as if they were strings, even if they are not wrapped in quotation marks. For example, the key in the object {pi: 3.142} is really "pi", and in {3.142: "pi"} the key is not the number 3.142 but the five-character string "3.142". When a key is a string that includes whitespace characters, quotation marks are mandatory: {"the key": "the value"}. Moreover, with such keys the object’s property values can be accessed only with the array-like notation obj["the key"]; the dotted form obj."the key" won’t work.

You can access object properties much as you do array elements, by putting the quoted key in square brackets. There’s also a shortcut “dotted” notation that is used much more often. Try it out (and remember you can edit this and add your own code):

As lines 6 and 7 show, you can add new key:value pairs; in line 8, we alter the value of an existing property. There are also provisions for deleting properties and iterating through all the properties of an object.

Objects provide a versatile scheme for storing and retrieving almost any kind of information. As a matter of fact, just about everything in JavaScript is an object when you look under the covers.

Variables

A rite of passage when you go from elementary school arithmetic to high school algebra is the introduction of variables—when you learn to solve for x. Variables are also crucial to computer programming, although their semantics is subtly different. The mathematical equation x = y + 1 states a relationship: The value of x is equal to y + 1, no matter what the specific values of x and y happen to be at any given moment. In JavaScript, x = y + 1 is not an equation but an assignment statement; when the statement is executed, it looks up the current value of y at that moment, adds 1, then sets the value of x equal to the result. The equation states something; the assignment statement does something.

In several of the code snippets above, you have already seen variables and assignment statements. Variables are introduced (or declared) with the keyword var. You can assign the variable an initial value if you wish, and you can bundle several declarations into a single statement.

If you neglect to declare a variable, JavaScript won’t complain. However, the undeclared variable will have global scope: It will be accessible everywhere in the program, and perhaps even in other JavaScript programs running on the same web page. That’s asking for trouble, since the same variable name could be used elsewhere for another purpose.

Variable names (a.k.a., identifiers) can be spelled with uppercase and lowercase letters as well as the underscore and dollar sign characters (_, $). Decimal digits are also allowed, except that a digit cannot be the first character. Nothing else is allowed in a name, in particular no spaces or hyphens or other punctuation. Case matters: Lex, lex, and LEX are all different identifiers. A common practice among JavaScripters is to write names in CamelCase: Words are squished together, with the first letter of each word capitalized. Names of variables and functions are done in sulkingCamelCase, with the very first letter lowercased, but objects are named in PrancingCamelCase, with head held high.

It’s worth emphasizing that the JavaScript system doesn’t care in the least what you name your functions and variables (as long as the names are legal). function add1(n) { return n + 1; } and function whynot(asparagus) { return asparagus + 1; } perform exactly the same computation. Choose names that are meaningful to you.

A JavaScript variable can hold any kind of value, and the data type can change whenever the variable is assigned a new value. In the sequence of statements var r = 4; r = "NESW"; r = ['a', 'b', 'c'], r holds first a number, then a string, and finally an array.

Comparisons

As noted above, the JavaScript statement x = y + 1 assigns to x the value y + 1. The expression x === y + 1 is quite different. This one asks a question—Is x equal to y + 1?—and returns a value of true or false as the answer. For example:

JavaScript actually has two equality operators, == and ===. The triple equal sign applies a stricter standard of what it means for two things to be equal; you’ll seldom go wrong if you stick to the strict one. Likewise the two inequality operators, != and !==, differ on what it means to be different. Again, the strict version !== is preferred.

The difference between the two equality operators shows up when you compare values that have different data types, such as a number and a string. For example, 0 === "0" returns false, but 0 == "0" returns true because JavaScript converts the string to a number.

Alongside the equality/inequality operators are four more operators that define the relations greater-than (>), less-than (<), greater-than-or-equal (>=), and less-than-or-equal (<=). Applying these comparisons to numerical values is straightforward. They are also defined for text strings, with the notion of greater and less determined by alphabetical order.

If, Then, Else

The usual reason for comparing data elements is to make decisions that control the sequence of events in a program. If x is greater than y, do one thing; if not, do another. In JavaScript this branching process works as follows:

Immediately following the keyword if is an expression wrapped in parentheses, called a predicate; the predicate must return a value that JavaScript can interpret as either true or false. (The parentheses are mandatory, by the way.) The next statement or block of statements, called the consequent, is executed if the predicate is true; if the predicate is false, the consequent is ignored. The else clause is optional. If an else is present, the statement labeled alternative is executed.

A single if statement is usually easy to understand, but the logic can grow tangled when multiple ifs and elses are combined or nested inside one another.

JavaScript has two other variations on this theme of making choices. The switch statement allows for multiway decisions. If an expression can return three possible values—say, "yes", "no", and "maybe"—a single switch statement can direct the program down three different pathways. The conditional operator is like the if statement in that it handles just two options, but instead of executing one statement or another, it returns one value or another.

Loops

Running around in circles sounds unproductive, but looping or iteration is an essential element of almost all programs. JavaScript has two main constructs for looping, called for and while.

A for loop executes a block of statements for a fixed number of times.

Well, the number of iterations isn’t necessarily fixed. If you fiddle with the index variable in the body of the loop, anything could happen. Not recommended. There is also a break statement that prematurely exits the loop.

The soup of symbols in parentheses on line 3 is what controls the iteration. It has three parts. First, i = 1; gives the loop counter, or index, an initial value of 1. This statement is executed just once, when the for loop is first entered. Next, i <= n; is a test applied just before each pass through the loop. If the test returns true, looping continues; otherwise, the whole process comes to an end. Third, i = i + 1 updates the value of i at the end of each iteration.

The statement on line 4 is the body of the loop; this is what gets executed repeatedly, in this case n times. On each interation, result is multiplied by the current value of i. When the looping is done, result has accumulated a value of 1 × 2 × 3 × . . . × n, which is called the factorial of n.

Quick exercise: Put a console.log() statement inside the loop, so that you can see a running record of how the value of result grows with each interation. Answer.

for (i = 1; i <= n; i = i + 1) { result = result * i; console.log(i, result); }

By the way, statements like i = i + 1 are often written in the shortcut notation i += 1, where the += does both the addition and the assignment. There’s a whole set of such shortcuts, including -=, *=, and /=. And there are even shorter shortcuts when all you need to do is add or subtract 1: i++ and i--.

A while loop keeps repeating a block of statements until some stated condition is no longer true. In the code below, the controlling condition is (n >= 0). In the body of the while loop, we multiply result by the current value of n. The output of the function is identical to that of the for-loop version above. But if you put a console.log() statement inside the loop, you’ll see that the computation takes a different path to that answer.

The for and while loops look different on the page, but they are hardly distinguishable at a deeper level. The choice is often a matter of taste or temperament. Still another way of getting the same answer really is different. The process is known as recursion.

This time there’s no explicit looping structure in evidence—no for, no while. Instead, there’s an if statement, and a call to the very function we are in the midst of defining. The basic idea is that calculating the factorial of n is easy if you happen to know the factorial of n – 1: Just multiply by n. So you “recurse” back through successively smaller values of n until you eventually come to n = 1, where there’s no more work to do.

Scripting the Web

So far, we’ve been writing code whose only way of talking back to us is by posting messages to the console. That’s a useful protocol for learning the language and for testing and debugging, but it’s not how most JavaScript programs behave. Instead, they create or manipulate elements of the web page in which they are embedded. Here’s a trivial example, just to illustrate how JavaScript is able to grab hold of web page content and change its appearance. When you click the Run button for the function below, all the subheadings in this page turn bright blue. (Click again to restore the original gray color.)

To understand what’s going on here, you need to know not just JavaScript but also the other languages that go into making things on the Web: HTML, or Hypertext Markup Language, and CSS, or Cascading Style Sheets. (Three languages just to put a splash of color on the screen! Yes, it’s a bit much, but it’s not totally crazy. HTML is for the substance of the page, the content and structure—the nouns. CSS describes how things look—the adjectives. JavaScript makes it move—the verbs.)

The best way to see what's happening when the program runs is to open up your browser’s developer tools and have a look at the HTML source code of this web page. Put your mouse pointer on the subhead “Scripting the Web” and right-click; in the drop-down menu, find and select the item “Inspect Element.” A new panel will open, showing the HTML source code with the subheading highlighted. It will look like this:

This should work in all of the major browsers. If you’re on a Macintosh with a one-button mouse, “right-click” === “option-click”. There are also menu commands to open the inspector.

<h4>Scripting the Web</h4>

Or maybe like this, if you have run the bluheds program an odd number of times:

<h4 style="color: blue">Scripting the Web</h4>

If you now press the Run button a few times more, you’ll see exactly what the bluheds function is doing. It inserts and removes a style="color: blue" annotation within the <h4> HTML tag.

HTML tags, characteristically enclosed in angle brackets, label the elements of an HTML document. <h4> is a level-four heading, <p> is a paragraph, and so on. Almost all of them require a matched closing tag, such as </p>

Let’s go through the function line by line. The document.getElementsByTagName("h4") method sifts through the entire web page and compiles a list of all elements tagged <h4>; the list, packaged as a special kind of array, is assigned to the variable subheds. The for loop steps through the array and examines each <h4> element in turn. If the element already has a style attribute specifying color: "blue", the removeAttribute method is invoked. It does just what the name suggests, removing the entire style attribute from the <h4> element. Otherwise, a new style.color = "blue" attribute is added to the element. The browser does the rest, reading the attributes of each element and displaying it appropriately.

Removing the entire attribute is not really the best way to do this. The element might have other styles applied, and bluheds would clobber them all. A better strategy is to add and remove a class attribute, such as class="blue", and then put the styling information in a separate CSS file.

The basic strategy employed by the bluheds function is a very common one in JavaScript programs. First you gather together all the HTML elements you want to work with, and store pointers to them in a JavaScript variable. Then you act on the elements one by one. You can also create new elements or delete existing ones. It’s a pretty simple recipe, but with a computer that can chomp through many thousands of elements per second, it can achieve some stunning visual effects.

Graphics

For scientific visualizations, you need more than multicolor subheads. You need graphics: the ability to draw or paint on the screen. JavaScript has access to two graphics systems within the browser, called the canvas element and Scalable Vector Graphics, or SVG. Although they work quite differently, for many purposes they can produce similar results. On a canvas you draw by invoking methods such as arc() or line(), which paint the appropriate pixels. Once such an object has been drawn, you can no longer move it or change it or even erase it. You can only paint a new object over it. SVG constructs a drawing from persistent graphical objects, closely analogous to the elements of an HTML document. You can move them around or alter their properties, and the displayed drawing will change to match. SVG is more versatile but also more complicated. Here we’re going to construct an elementary demo of drawing on the canvas.

The rectangle above is a blank canvas. If you do an Inspect Element on it, you’ll find it has an id of bubbles-canvas. The canvas is blank because we haven’t yet drawn anything in it. Press the Run button to fix that.

How does it work? The comments in the code will explain much, but I’d like to call attention to a few more points.

There are lots of opporunties for exploring and experimenting with this code. At the simplest level, you might change the number of bubbles to draw or the rate at which they are drawn. Or make the bubbles hollow by changing fill() to stroke() and fillStyle to strokeStyle.) If you’re feeling more ambitious, you could try drawing rectangular bubbles. The Mozilla reference on canvas will tell you how that’s done. You’re in charge here.

What’s Next

If you’d like to get a head start on a project of your own, download templates.zip, which has skeleton versions of HTML, CSS, and JavaScript files you can use as a starting point. You can open them all in the Brackets editor. Or you might want to take a look at a little project of mine that I discussed at the NESW workshop. Finally, you might want to peruse the source code of this tutorial in the workshop’s GitHub repository.