Chapter 2
Program Structure

In this chapter, we will expand our command of the JavaScript language beyond the nouns and sentence fragments we’ve seen so far, to the point where we can express some meaningful prose.

Expressions and statements

In Chapter 1, we made some values and then applied operators to them to get new values. Creating values like this is an essential part of every JavaScript program, but it is only a part.

A fragment of code that produces a value is called an expression. Every value that is written literally (such as 22 or "socialism") is an expression. An expression between parentheses is also an expression (like (1 + 2)), as is a binary operator applied to two expressions (like "hello " + "there!") or a unary operator applied to one (like !true).

This shows part of the beauty of a language-based interface. Expressions can nest in a way very similar to the way subsentences in human languages are nested—a subsentence can contain its own subsentences, and so on. This allows us to combine expressions to express arbitrarily complex computations.

If an expression corresponds to a sentence fragment, a JavaScript statement corresponds to a full sentence in a human language. A program is simply a list of statements.

The simplest kind of statement is an expression with a semicolon after it. This is a program:

1;
!false;

It is a useless program, though. An expression can be content to just produce a value, which can then be used by the enclosing expression. A statement stands on its own and amounts to something only if it affects the world. It could display something on the screen—that counts as changing the world—or it could change the internal state of the machine in a way that will affect the statements that come after it. These changes are called side effects (we’ll see an example of a side effect in the next section!). The statements in the previous example just produce the values 1 and true and then immediately throw them away. This leaves no impression on the world at all. When executing the program, nothing observable happens.

In some cases, JavaScript allows you to omit the semicolon at the end of a statement. In other cases, it has to be there, or the next line will be treated as part of the same statement. The rules for when it can be safely omitted are somewhat complex and error-prone. In this book, every statement that needs a semicolon will always be terminated by one. I recommend you do the same in your own programs, at least until you’ve learned more about subtleties involved in leaving out semicolons.

Variables

How does a program keep an internal state? How does it remember things? We have seen how to produce new values from old values, but this does not change the old values, and the new value has to be immediately used or it will dissipate again. To catch and hold values, JavaScript provides a thing called a variable.

var caught = 5 * 5;

And that gives us our second kind of statement. The special word (keyword) var indicates that this sentence is going to define a variable. It is followed by the name of the variable, an = operator, and an expression.

The previous statement creates a variable called caught and uses it to grab hold of the number that is produced by multiplying 5 by 5.

After a variable has been defined, its name can be used as an expression. The value of such an expression is the value the variable currently holds. Here’s an example:

var ten = 10;
print(ten * ten);
// → 100

Variable names can be any word that isn’t a reserved word (such as var). They may not include spaces. Digits can also be part of variable names—catch22 is a valid name, for example—but the name must not start with a digit. A variable name cannot include punctuation, except for the characters $ and _.

A single var statement may define multiple variables. The definitions must be separated by commas.

var one = 1, two = 2;
print(one + two);
// → 3

Keywords and reserved words

Words with a special meaning, such as var, are keywords, and they may not be used as variable names. There are also a number of words that are “reserved for use” in future versions of JavaScript. These are also officially not allowed to be used as variable names, though some JavaScript environments do allow them. The full list of keywords and reserved words is rather long.

break case catch class const continue debugger
default delete do else enum export extends false
finally for function if implements import in
instanceof interface let new null package private
protected public return static super switch this
throw true try typeof var void while with yield

Don’t worry about memorizing these, but remember that this might be the problem when a variable definition does not work as expected.

The environment

The collection of variables and their values that exist at a given time is called the environment. When a program starts up, this environment is not empty. It always contains variables that are part of the language standard, and most of the time, it has variables that provide ways to interact with the surrounding system. For example, in a browser, there are variables and functions to inspect and influence the currently loaded website and to read mouse and keyboard input.

Functions

Up until now, every value (numbers, images, booleans) we have created have been unchanging - even with our most complicated images, they don’t change. Sometimes, we want to be able to create values that are based on other values. For example, we might want to make an image where the color could vary, based on how we wanted to use it. To do this, we create functions. A function is a specification for how to create a value depending on some other values, which are alternatively called arguments or parameters. Functions can also cause side effects (for example, our print function causes values to be shown on the screen - previously, we referred to print as an operator, to make it analogous to + or *, but function is the proper name). Even though they are quite a bit more sophisticated, functions are values just like numbers, strings, and images - they can be passed as arguments, stored in variables, etc.

We define functions with the function keyword. For example, the following code defines the variable square to refer to a function that produces the square of a given number:

var square = function(x) {
  return x * x;
};

print(square(12));
// → 144

The function keyword is followed by parenthesis, and within those are a comma-separated list of argument names. When you apply the function, these names will be where the input values are. The body of the function (between the { and }) should eventually produce a value (it can also do other things first). To produce a value, you use the return keyword. There is a little more about return in the next section.

Using a function is called invoking, calling, or applying it. You can call a function by putting parentheses after an expression that produces a function value. Usually you’ll directly use the name of the variable that holds the function. We can also define a new name for square, and use that instead:

var square = function(x) {
  return x * x;
};

var my_better_square = square;
print(square(12));

Built in functions like print can also be given new names:

var my_better_print = print;
my_better_print("Hello there!");

The values between the parentheses are given to the program inside the function. In the example, the square function uses the integer 12 that we give it as the text to show. Values given to functions are called arguments. The square function needs only one of them, but other functions might need a different number or different types of arguments.

Return values

Writing text to the screen is a side effect. But functions produce values, and these are usually why we want to use them. For example, the function Math.max takes any number of number values and gives back the greatest.

print(Math.max(2, 4));
// → 4

The value that a function produces is called the return value, and the function is said to have returned the value. Anything that produces a value is an expression in JavaScript, which means function calls can be used within larger expressions. Here a call to Math.min, which is the opposite of Math.max, is used as an input to the plus operator:

print(Math.min(2, 4) + 100);
// → 102

Dots in function names

Though variable names cannot contain period characters, Math.max clearly has one. This is because Math.max isn’t a simple variable. It is actually an expression that retrieves the max property from the value held by the Math variable. We will go into more detail on this later, but for now, you can use these identifiers the same way you would your own variables.

Comments

Often, raw code does not convey all the information you want a program to convey to human readers, or it conveys it in such a cryptic way that people might not understand it. At other times, you might just feel poetic or want to include some thoughts as part of your program. This is what comments are for.

A comment is a piece of text that is part of a program but is completely ignored by the computer. JavaScript has two ways of writing comments. To write a single-line comment, you can use two slash characters (//) and then the comment text after it.

A // comment goes only to the end of the line. A section of text between /* and */ will be ignored, regardless of whether it contains line breaks. This is often useful for adding blocks of information about a file or a chunk of program.

/*
 I first found this number scrawled on the back of one of
 my notebooks a few years ago. Since then, it has often
 dropped by, showing up in phone numbers and the serial
 numbers of products that I've bought. It obviously likes
 me, so I've decided to keep it.
*/
var myNumber = 11213;

More functions

A function can have multiple parameters or no parameters at all. In the following example, makeNoise does not list any parameter names, whereas emphasize lists two:

var makeNoise = function() {
  print("Pling!");
};

makeNoise();
// → Pling!

var emphasize = function(string) {
  return string + "!!!!";
};

print(emphasize("hello there"));
// → hello there!!!!

Some functions explicitly return a value, such as emphasize and square, and some don’t, such as makeNoise. A return statement determines the value the function returns. When control comes across such a statement, it immediately jumps out of the current function and gives the returned value to the code that called the function. The return keyword without an expression after it will cause the function to return undefined. If there is no return statement, your function also returns undefined.

For example:

var my_function = function() {

};
print(my_function());

Functions for drawing

You can create an empty scene with:

var scene = emptyScene(400,100);
print(scene);

And we can place a bicycle on that scene using the placeImage function, which is like overlay but it takes, additionally, how far from the left and top to place the first over the second image:

var scene = placeImage(bike, emptyScene(400,100), 0, 30);
print(scene);

We can move the bike across the scene:

print(placeImage(bike, emptyScene(400,100), 0, 30));
print(placeImage(bike, emptyScene(400,100), 100, 30));
print(placeImage(bike, emptyScene(400,100), 200, 30));
print(placeImage(bike, emptyScene(400,100), 300, 30));

Instead of just creating those scenes, we can write a function that, given the position of the bike, draws the scene.

var draw_bike = function(position) {
  return placeImage(bike, emptyScene(400,100), position, 30);
};
print(draw_bike(100));
print(draw_bike(200));
print(draw_bike(300));

This looks something like the images in a flip book, right? In a flip book, each page has a different image and you can view an animation by flipping the pages in sequence. So lets turn this into an animation!

TLC.js has a function called animate that can create animations from functions like this. It takes a function that returns an image (like our draw_bike). Then it calls that function with the number 0 and draws the image. It calls it again with 1, and draws that image... and the same for 2, 3 ,4... And keeps going forever, feeding your function increasing numbers and drawing the result.

animate uses JavaScript’s native animation functions that try to draw 60 frames per second. You can think of each frame as one page in the flip book. The browser’s JavaScript engine can only do one thing at a time, so if there are lots of animations on a page, it will try to draw one frame from each of them before moving on to the next frame. That’s why webpages with many animations can feel slow and choppy. The time between frames is longer! That time period is called a "tick", and the number of ticks since the animation starts is what is passed to the drawing function in animate.

var draw_bike = function(ticksSinceStart) {
  var xPosition = ticksSinceStart;
  return placeImage(bike, emptyScene(400,100), xPosition, 30);
};
animate(draw_bike);

A shorter way to define functions

Since giving names to functions by storing them in variables is really common, there is a shorter way to do these two things:

var name = function(arg) { return arg; };
// Is equivalent to:
function name(arg) { return arg; }

The second is a little shorter and doesn’t have a semicolon at the end.

Parameters and scopes

The parameters to a function behave like regular variables, but their initial values are given by the caller of the function, not the code in the function itself.

An important property of functions is that the variables created inside of them, including their parameters, are local to the function. This means that any variables defined within functions will be newly created every time the function is called, and these separate incarnations do not interfere with each other.

This “localness” of variables applies only to the parameters and to variables declared with the var keyword inside the function body. Variables declared outside of any function are called global, because they are visible throughout the program. It is possible to access such variables from inside a function, as long as you haven’t declared a local variable with the same name.

The following code demonstrates this. It declares the variable as local and thus changes only the local variable, which is unchanged.

var x = "outside";

var f1 = function() {
  var x = "inside f1";
};
f1();
print(x);
// → outside

This behavior helps prevent accidental interference between functions. If all variables were shared by the whole program, it’d take a lot of effort to make sure no name is ever used for two different purposes. By treating function-local variables as existing only within the function, the language makes it possible to read and understand functions as small universes, without having to worry about all the code at once.

Animation

animate calls your drawing function with a number. That number represents how many "ticks" have happened since the animation started.

Note: in the following, we want to turn a number (of ticks) into an image. We have a function called text that takes a string (like "hello") and turns it into an image. So if we could first take our number (like 12 and turn it into a string "12"), then we could turn it into an image with text. Javascript has a built in function that is called String that does just that. You can see it in use in the below example. If you are trying to do the reverse (turn a string like "1001" into the number 1001), there is a corresponding function Number.

function show_how_many_ticks(ticksSinceStart) {
  return text(String(ticksSinceStart), 16);
}

animate(show_how_many_ticks);

This number (corresponding to the annoying linear nature of time as we conventionally experience it) is always getting bigger at a constant rate. So it makes sense that we can use it to create an animation of something growing or moving forward:

function growingCircle(time) {
  var size = time;
  return overlay(circle(size, "red"), emptyScene(200, 200));
}

animate(growingCircle);

function movingCircle(time) {
  var xPosition = time;
  return placeImage(circle(10, "black"), emptyScene(200, 30), xPosition, 5);
}

animate(movingCircle);

But while a steady march forward into infinity isn’t a terrible approximation of how we experience changes in time, it’s still not a very useful way to represent how things change shape or position. Things don’t always grow, sometimes they shrink. Things move backwards as well as forwards. And sometimes they move faster or slower. How do we take a number that is always getting bigger (the amount of time that has passed) and turn it into a number that changes in a different way?

We can think about the different tools we have already. We have lots of operators: -, +, *, and /. We’ll also introduce a new operator, % (pronounced "mod"). Let’s see what happens when we use these operators with animate!

Hmmm. All these operators can take two arguments. One of them is going to be time, but we need another number. This is just an experiment so lets pick any number... How about 100?

function adding(time) {
  return text("100 + the current time (" + String(time) + ") is " + (100 + time), 16);
}

animate(adding);
function subtracting(time) {
  return text("100 - the current time (" + String(time) + ") is " + String(100 - time), 16);
}

animate(subtracting);
function multiplying(time) {
  return text("100 * the current time (" + String(time) + ") is " + String(100 * time), 16);
}

animate(multiplying);
function dividing(time) {
  return text("100 / the current time (" + String(time) + ") is " + String(100 / time), 16);
}

animate(dividing);

Now for the new operator:

// `%` divides by the number by another number and returns
// the remainder
function modding(time) {
  return text("the current time (" + String(time) + ") % 100 is " + String(time % 100), 16);
}

animate(modding);

So you can see that the time going into the function is always increasing at the same rate, just like before. But now, some of the resulting numbers are increasing and some are decreasing, and they are doing that at different rates!

What does that look like when we apply it to images?

function adding1(time) {
  var radius = 100 + time;
  return overlay(circle(radius, "red"), emptyScene(200, 200));
}

function adding2(time) {
  var xPosition = 100 + time;
  return placeImage(circle(10, "black"), emptyScene(200, 30), xPosition, 5);
}

animate(adding1);
animate(adding2);
function subtracting1(time) {
  var radius = 100 - time;
  return overlay(circle(radius, "red"), emptyScene(200, 200));
}

function subtracting2(time) {
  var xPosition = 100 - time;
  return placeImage(circle(10, "black"), emptyScene(200, 30), xPosition, 5);
}

animate(subtracting1)
animate(subtracting2);

The next two cause changes so fast or so slow that it’s hard to even see.

function multiplying1(time) {
  var radius = time * 100;
  return overlay(circle(radius, "red"), emptyScene(200, 200));
}

function multiplying2(time) {
  var xPosition = time * 100;
  return placeImage(circle(10, "black"), emptyScene(200, 30), xPosition, 5);
}

animate(multiplying1);
animate(multiplying2); // moves so fast you can't even see it!
function dividing1(time) {
  var radius = time / 100;
  return overlay(circle(radius, "red"), emptyScene(200, 200));
}

function dividing2(time) {
  var xPosition = time / 100;
  return placeImage(circle(10, "black"), emptyScene(200, 30), xPosition, 5);
}

animate(dividing1);
animate(dividing2); // moves so slow you can hardly tell!

Try multiplying and dividing by 10 instead of 100 and see what happens! Try even smaller numbers and bigger numbers!

function modding1(time){
  var radius = time % 100;
  return overlay(circle(radius, "red"), emptyScene(200, 200));
}

function modding2(time){
  var xPosition = time % 100;
  return placeImage(circle(10, "black"), emptyScene(200, 30), xPosition, 5);
}

animate(modding1);
animate(modding2);

Using % in animation creates a looping effect! How would you make the circle in modding2 go all the way to the end of the box?

Fluid movement with sin

Another fun function for making animations is Math.sin. This is the sin function from math. You can fiddle with this to get interesting things to happen:

function sinWiggle(ticksSinceStart) {
  var xPosition = Math.sin(ticksSinceStart/20) * 90 + 90;
  return placeImage(circle(10, "black"), emptyScene(200, 30), xPosition, 5);
}

animate(sinWiggle);

The cool thing about sin and cos is that Math.sin(anything) and Math.cos(anything) are always numbers between -1 and 1.

print(Math.sin(0));
print(Math.sin(100));
print(Math.sin(500000));

If you multiply the result of sin(some number) by 90, you will always get a number between -90 and 90.

print(Math.sin(0) * 90);
print(Math.sin(100) * 90);
print(Math.sin(500000) * 90);

We use that fact in sinWiggle. We multiple by 90 to always get a number between -90 and 90. Then we add 90, so the number is always between 0 and 180.

print(Math.sin(0) * 90 + 90);
print(Math.sin(100) * 90 + 90);
print(Math.sin(500000) * 90 + 90);

So sinWiggle takes a number, no matter how big, and turns that into an image placing a dot. A helpful operator is %, which is pronounced mod. It takes the remainder after diving the right side by the left side.

Control flow

When your program contains more than one statement, the statements are executed, predictably, from top to bottom. As a basic example, this program has two statements.

print(bike);
print(circle(100, "green"));

Here is the rather trivial schematic representation of straight control flow:

Trivial control flow

Conditional execution

Executing statements in straight-line order isn’t the only option we have. An alternative is conditional execution, where we choose between two different routes based on a Boolean value, like this:

Conditional control flow

Conditional execution is written with the if keyword in JavaScript. In the simple case, we just want some code to be executed if, and only if, a certain condition holds. For example, we can write a function that returns one message if a number is bigger than zero and another if it is smaller!

var sign = function(number) {
  if (number > 0) {
    return "it's a positive number";
  } else {
    return "it's not a positive number";
  }
};

print(sign(8));
print(sign(0));
print(sign(-15));

If we have more than two paths to choose from, multiple if/else pairs can be “chained” together. We can use that to make our message more informative:

var sign = function(number) {
  if (number > 0) {
    return "it's a positive number";
  } else if (number === 0) {
    return "it's zero";
  } else {
    return "it's a negative number";
  }
};

print(sign(8));
print(sign(0));
print(sign(-15));

The flow chart for this program looks something like this:

Nested if control flow

We can also use this to improve our bike animation. Previously, when the bike reached the edge of the scene, it kept going. Instead, we can make it stop!

var draw_bike = function(position) {
  if (position > 300) {
    return placeImage(bike, emptyScene(400,100), 300, 30);
  } else {
    return placeImage(bike, emptyScene(400,100), position, 30);
  }
};
animate(draw_bike);

Exercises

  1. Magical Teleporting Bike

Let’s try making a magical teleporting bike!

This magical bike rides on the ground for the first part of its journey. When it reaches the carefully guarded, top secret, Original Magic Teleportation Point (known to UFO buffs as Position 80), it jumps up into the sky! When it reaches the next Magical Teleportation Point (known by the initiate as Position 160), it jumps back down to the ground. When it reaches the end of its Magical Road (at the pitstop locals like to call Position 320), it stops.

We’ve sketched out a skeleton of what a program for creating such a Magical Teleporting Bike might look like below. Try replacing the comments with running code and giving the Magical Teleporting Bike for a spin!

var draw_bike = function(position) {
  if (position < 80) {
    return placeImage(bike, emptyScene(400,100), position, 30);
  } else if (position < 160) {
    // jump to the top!
  } else if (position < 320){
    // jump back to the bottom!
  } else {
    // stop!
  }
};

animate(draw_bike);
  1. Make an image you already made move!

In chapter 1, at the end, you may have drawn an image. Now that you have animate, you should be able to make some part (or many parts) of your image move.

  1. Extra credit: Go Backwards!

Can you think of a way to replace the comment with code that will make the bike go backwards once it reaches the right-most part of the scene?

var draw_bike = function(position) {
  if (position < 400) {
    return placeImage(bike, emptyScene(400, 100), position, 30);
  } else {
    return placeImage(bike, emptyScene(400, 100), /*what goes here?*/ 30)
  };
};

animate(draw_bike);
  1. Extra credit: Back and forth forever

Using mod, can you figure out how to make the bike run back and forth across the screen forever?

Summary

You now know that a program is built out of statements, which themselves sometimes contain more statements. Statements tend to contain expressions, which themselves can be built out of smaller expressions.

Putting statements after one another gives you a program that is executed from top to bottom. You can introduce disturbances in the flow of control by using conditional (if, else if, else) statements.

Variables can be used to file pieces of data under a name, and they are useful for organizing your program. The environment is the set of variables that are defined. JavaScript systems always put a number of useful standard variables into your environment.

Functions are special values that encapsulate a piece of program. You can invoke them by writing functionName(argument1, argument2). Such a function call is an expression, and produces a value.