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.
A 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 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 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
A 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) } } /* # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # */