Blog

JavaScript Program Structure
Posted on May 26, 2019 in JavaScript by Matt Jennings

Note: Information below was taken from Eloquent JavaScript, 3rd edition, Chapter 2 Program Structure.

Expressions

A fragment of code that produces a value is called an expression. Every value that is written literally (such as 22 or "psychoanalysis") is an expression. An expression between parentheses is also an expression, as is a binary operator applied to two expressions or a unary operator applied to one.

statement is an instructions, an action.

// The 1, !false, !!false below
// are expressions
console.log(1)
// 1
console.log(!false)
// true
console.log(!!false)
// false

// In JavaScript, a statement is an instruction,
// an action
// The statement below is the if and else
// statement
// Output is 5
var num = 5
if(num > 0) {
    console.log(num)
}
else {
    console.log(0)
}

Bindings

To catch and hold values, JavaScript provides a thing called a binding, or variable.

Binding names

Binding names can be any word. Digits can be part of binding names—catch22 is a valid name, for example—but the name must not start with a digit. A binding name may include dollar signs ($) or underscores (_) but no other punctuation or special characters.

The environment

The collection of bindings 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 bindings that are part of the language standard, and most of the time, it also has bindings that provide ways to interact with the surrounding system.

Functions

A lot of the values provided in the default environment have the type function. A function is a piece of program wrapped in a value. Such values can be appliedin order to run the wrapped program. For example, in a browser environment, the binding prompt holds a function that shows a little dialog box asking for user input.

prompt("Enter passcode");

Executing a function is called invokingcalling, 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 binding that holds the function. The values between the parentheses are given to the program inside the function.

Values given to functions are called arguments. Different functions might need a different number or different types of arguments.

Return values

Showing a dialog box or writing text to the screen is a side effect. A lot of functions are useful because of the side effects they produce. Functions may also produce values, in which case they don’t need to have a side effect to be useful. For example, the function Math.max takes any amount of number arguments and gives back the greatest.

console.log(Math.max(2, 4));
// 4

When a function produces a value, it is said to return that value. Anything that produces a value is an expression in JavaScript, which means function calls can be used within larger expressions. 

Control flow

When your program contains more than one statement, the statements are executed as if they are a story, from top to bottom. 

Conditional execution

Not all programs are straight roads. We may, for example, want to create a branching road, where the program takes the proper branch based on the situation at hand. This is called conditional execution.

Conditional execution is created with the if keyword in JavaScript. In the simple case, we want some code to be executed if, and only if, a certain condition holds.

The statement after the if is wrapped in braces ({ and }) in this example. The braces can be used to group any number of statements into a single statement, called a block. You could also have omitted them in this case, since they hold only a single statement, but to avoid having to think about whether they are needed, most JavaScript programmers use them in every wrapped statement like this.

if (1 + 1 === 2) console.log("It's true");
// "It's true"

while and do loops

What we need is a way to run a piece of code multiple times. This form of control flow is called a loop.

Looping control flow allows us to go back to some point in the program where we were before and repeat it with our current program state. If we combine this with a binding that counts, we can do something like this:

let number = 0;
while (number <= 12) {
  console.log(number);
  number = number + 2;
}
// 0
// 2
// etc.

As an example that actually does something useful, we can now write a program that calculates and shows the value of 210 (2 to the 10th power). We use two bindings: one to keep track of our result and one to count how often we have multiplied this result by 2. The loop tests whether the second binding has reached 10 yet and, if not, updates both bindings.

let result = 1;
let counter = 0;
while (counter < 10) {
  result = result * 2;
  counter = counter + 1;
}
console.log(result);
// 1024

do loop is a control structure similar to a while loop. It differs only on one point: a do loop always executes its body at least once, and it starts testing whether it should stop only after that first execution. To reflect this, the test appears after the body of the loop.

This program will force you to enter a name. It will ask again and again until it gets something that is not an empty string. Applying the ! operator will convert a value to Boolean type before negating it, and all strings except ""convert to true. This means the loop continues going round until you provide a non-empty name.

for loops

JavaScript and similar languages provide a slightly shorter and more comprehensive form, the for loop.

for (let number = 0; number <= 12; number = number + 2) {
  console.log(number);
}
// 0
// 2
// etc.

The parentheses after a for keyword must contain two semicolons. The part before the first semicolon initializes the loop, usually by defining a binding. The second part is the expression that checks whether the loop must continue. The final part updates the state of the loop after every iteration. In most cases, this is shorter and clearer than a while construct.

let result = 1;
for (let counter = 0; counter < 10; counter = counter + 1) {
  result = result * 2;
}
console.log(result);
// 1024

Breaking Out of a Loop

Having the looping condition produce false is not the only way a loop can finish. There is a special statement called break that has the effect of immediately jumping out of the enclosing loop.

This program illustrates the break statement. It finds the first number that is both greater than or equal to 20 and divisible by 7.

for (let current = 20; ; current = current + 1) {
  if (current % 7 == 0) {
    console.log(current);
    break;
  }
}
// 21

If you were to remove that break statement or you accidentally write an end condition that always produces true, your program would get stuck in an infinite loop. A program stuck in an infinite loop will never finish running, which is usually a bad thing.

Updating bindings succinctly

Especially when looping, a program often needs to “update” a binding to hold a value based on that binding’s previous value.

counter = counter + 1;
// Long hand to write

counter += 1;
// Shortcut to write above

result *= 2
// Double a result

counter -= 1
// Count downward

counter += 1
// Longhand

counter++
// Shorthand

counter -= 1
// Longhand

counter--
// Shorthand

This allows us to shorten our counting example a little more.

for (let number = 0; number <= 12; number += 2) {
  console.log(number);
}
// 0
// 2
// 4
// 6
// 8
// 10
// 12

Dispatching on a value with switch

There is a construct called switch that is intended to express such a “dispatch” in a more direct way.

switch (prompt("What is the weather like?")) {
  case "rainy":
    console.log("Remember to bring an umbrella.");
    break;
  case "sunny":
    console.log("Dress lightly.");
  case "cloudy":
    console.log("Go outside.");
    break;
  default:
    console.log("Unknown weather type!");
    break;
}

You may put any number of case labels inside the block opened by switch. The program will start executing at the label that corresponds to the value that switch was given, or at default if no matching value is found. It will continue executing, even across other labels, until it reaches a break statement.

Exercises

Looping a triangle

let hash = '#';
for(let count = 1; count <= 7; count++) {
  hash += '#'
  console.log(hash);
}

/*
#
##
###
####
#####
######
#######
*/

FizzBuzz

for(let num = 1; num <= 100; num++) {
  if(num % 3 === 0 || num % 5 === 0) {
    console.log(num)
  }
}
// FizzBuzz 1 to 100

Chessboard

const odd = ' # # # #'
const even = '# # # # '
for(let i = 1; i <= 8; i++) {
  if(i % 2 !== 0) {
    console.log(odd)
  }
  else {
    console.log(even)
  }
}

/*
 # # # #
# # # # 
 # # # #
# # # # 
 # # # #
# # # # 
 # # # #
# # # #
*/

Leave a Reply