New Book: Full-stack JavaScript Web Development — From A to Z

The first 4 prep chapters

Samer Buna
EdgeCoders
Published in
38 min readJun 26, 2018

--

Buckle up… This book will take you on a long and bumpy ride.

Chapter 0: Introduction

Chapter 1: Programming 101

Chapter 2: The Basic Syntax Review

Chapter 3: Scopes and Loops

Chapter 0: Introduction

Yes, programmers count from ZERO… Make peace with that.

I had the privilege of starting to learn how to code at a young age. While this has its advantages, I think it is never too late to start learning. It may be a bit harder to create the necessary coding habits, but it is totally worth it — and not just financially. Coding is my hobby and I hope for you to join the club, one whose members make money doing what they absolutely love to do, and are willing to do, just for fun.

Learning how to write computer programs is fun, but it is not easy. However, getting started to understand the basic concepts of programming is easy and it is what this first section of the book is all about. If you are someone whose entire coding experience is only from hearing others talk about how cool coding is, this section is for you. It will transform you into someone who can write simple programs to solve actual problems.

Why JavaScript

You may have heard that JavaScript is not the best of computer languages. This is somewhat true.

JavaScript was initially designed by Brendan Eich in about 10 days, which is a very short period of time to design a computer language and it resulted in the language having a lot of problems and “bad parts”. For the longest time, professional software developers did not like JavaScript because of its quirks and odd behaviors. However, this is changing today.

I was one of these skeptical software developers just a few years ago. However, today I am in love with JavaScript. I even totally broke up with the beautiful Ruby (after a 10-year relationship) to exclusively date JavaScript. I am happier with JavaScript.

JavaScript has changed significantly. The bad parts were removed and what remained turned out to be a beautiful and very flexible language. The TC39 committee, who is responsible for maintaining ECMAScript (the standard behind JavaScript), is carefully introducing more great features into the language.

Today, there are many reasons to adopt JavaScript, even as a first language:

  • JavaScript is the only language that can be used for true full-stack web development in major browsers.
  • JavaScript has the largest ecosystem of wonderful tools, libraries, and frameworks that are used by both small and big teams.
  • JavaScript code can be tested in the browser without any setup.
  • JavaScript is flexible to a fault. It can be whatever you need it to be (object-oriented, functional, procedural, imperative, declarative, event-driven, etc.)
  • JavaScript is dynamically typed, but you can easily add static-type checking during your development workflow. This uniquely positions the language to offer the great advantages of both coding styles, even in the same project.
  • JavaScript has no hard-to-read indentation-based (off-side) blocks.
  • JavaScript has a very small standard library that covers the absolute basics. Beyond that, you can pick what you need rather than having a large standard library of which you will likely only use a small part. The lack of a full standard library also forces you to write and test simple operations yourself, which is a plus.
  • Thanks to browsers and Node.js, JavaScript is — or can be — available on nearly every device you need to work with. You can be a productive programmer who only knows JavaScript.
  • JavaScript makes it easy for you to make mistakes, which speeds up your learning curve if you are generally following good practices about finding mistakes early.
  • Nearly every programmer on Earth knows a thing or two about JavaScript making it easy to find help.
  • JavaScript is controlled by a wonderful committee (TC39) who is diligent when it comes to adding new features to the language and deprecating old ones.
  • Many other languages compile to JavaScript. If the official syntax bothers you, there are options.
  • JavaScript is very popular and is not going away anytime soon. It is the safest long-term bet when picking a language to learn.

Chapter 1: Programming 101

This book’s subtitle is “From A-Z” and that is not a gimmick! If you know nothing about programming, these prep chapters got you covered. Let’s start from the very beginning…

What is a Computer Program?

Computers can read text and understand it in many different ways. A computer program is just some text programmers write for the purpose of having the computer translate it into instructions that the computer will later perform.

The story begins with writing that text, for example:

Add 5 to 2 then print the result to the screen

A computer program’s text is written in a language (a programming language). The language I used above is just English. However, we need to use one of the programming languages that computers can understand, like Java, Python, or JavaScript.

To write the computer program text above with JavaScript, here is the syntax that we need:

let result = 5 + 2;console.log(result);

We can now tell the computer to read this program’s text and translate it into instructions it can perform. Computers can only understand 1s and 0s, so the text above will be translated into a stream of 1s and 0s.

Something like:

001010000111010101110100011000000111011011100101011100110111010101111100001101000010100001111101011000000011010100110000110101100110000011100100111101100001110011010110100111101111110010100110111111101101110011101010000111001111100011111110110111100101010001100100111010101010011011001010110100001110110011010010010101101001010

Once the computer has instructions written in 1s and 0s, it can use its resources (like CPU, memory, network) to perform these instructions. For our example, it will use the CPU to do the math, the memory to save the result, and the screen pixels to show the result.

You can test the program text above in your browser’s development console or head to jscomplete.com/playground and paste the code in the editor panel and hit the “Run” button. The magic will happen in the background to display the answer in the preview panel.

Of course, this is a very simple program with clear instructions, but no matter how complicated the program gets it will remain just that: a set of instructions written in a programming language that the computer will translate and execute line by line.

To be able to write useful computer programs, you need to learn the syntax of a computer language. Programmers are fluent in their computer languages of choice just as they are fluent with their human languages. Fortunately, learning a computer language is a lot easier than learning a human language.

So in the program text that we wrote above in JavaScript, what is “let”, “console”, “log”, and why is every line terminated with a semicolon? This is all syntax in which you need to be fluent.

We will start with some basic concepts in this chapter. The next chapter will be a full overview of JavaScript syntax.

The Concepts of Variables and Expressions

let result = ...

In the line of code above, we are telling the computer to create a variable. A variable represents a storage unit, a place in the computer memory. The computer will simply reserve a space in its memory and label it as result.

You can actually instruct the computer to only reserve the space without any initial value set in it:

let undefVar;

With the line of code above, the computer will reserve the space in its memory and label it as undefVar. The value of this undefVar remains undefined.

However, when we defined the result variable in the previous section, we also instructed the computer to perform a mathematical operation, take the result of that operation, and place it in the memory space that is to be labeled as result.

This happened when we wrote 5 + 2, which is known as an expression in programmers’ terminology. This expression contains an operator (the + sign). The computer recognizes this operator and the integer values and it performs the math operation and figures out that this expression is equal to 7, which is the value it can now use to change the content of the memory space that will be labeled as result.

The computer understands many other operators. Go ahead and try the characters -, *, and / in place of the +.

You can also combine operators to solve more complex mathematical expressions. Try this expression, for example: 2.2 + 0.8 * 5. Note how the mathematical precedence rules apply here as well, and so is the use of parentheses to indicate an alternative. Try (2.2 + 0.8) * 5.

All of the expressions you attempted above resulted in values which were stored in the memory space labeled result.

The semicolon is JavaScript’s way of denoting the end of a line. Without it, the computer will attempt to join the next line with the current one. For example, the same addition example can be written on multiple lines like this:

let result = 5
+ 2;
console.log(result);

Since the first line does not have a semicolon, the computer continues to the line after it and only concludes the operation when it sees a semicolon.

Let’s now look at the next line. What is this console.log thing?!

The Concepts of Objects and Functions

In the new language terminology that we are learning, console is called an object and log is called a function. The log function is a property of the console object. Let’s walk through these new concepts one by one.

An object is a special variable in memory that represents a list of key-value pairs. It is a collection of memory spaces, not just a single space like what was reserved for the result variable above. Every memory space allocated for an object can be identified by a property on that object, which is often called a key. For example, here is an object with three memory spaces labeled result1, result2, and result3:

let obj = {
result1: 1 + 2;
result2: 3 + 4,
result3: 5 + 6,
};

In this example, the computer will allocate a collection of three memory spaces and collectively label them as obj. Then, it labels the first space as result1, puts a value of 3 there (after evaluating that expression), puts a value of 7 in the second space, and finally 11 in the third space.

We can read the values out of this object using the dot notation. For example, to use the value of the result2 property, we do:

obj.result2

We can also change the value of result2 using the same dot notation:

obj.result2 = 42;

We can also use the bracket notation to read and modify any property:

// Read Value
obj['result2']

// Modify Value
obj['result2'] = 42;

The bracket notation has its special uses but in most cases the dot notation is preferable. For now, just be aware that there is a bracket notation and always use the dot notation.

You can add and remove memory spaces (properties) from any object later on.

The console object above has a single memory space labeled log. That property has a special value stored in it: a function.

A function in a computer program is exactly like a function in Math. It is a relation between a set of inputs and a set of outputs.

After we define a function, we can call it. That is what we did with console.log; we called it with a single input: the result variable. To call a function in JavaScript, we simply use the parentheses syntax: functionName().

The console.log function takes the result input and prints it out to the console screen. It does not do any transformation on the input.

We did not need to define the console.log function because it is already defined internally in the browser’s engine. It is not part of the JavaScript language itself but rather added to the browser’s environment.

JavaScript comes with many other predefined functions. For example, there is a built-in Math object that has many mathematical constants and functions to calculate trigonometric operations, logarithms, square roots, exponent powers, and many other mathematical operations. Here are a few Math expressions you can explore:

console.log(
Math.pow(2, 5) // 3 to the power 5
);
console.log(
Math.log2(32) // Base 2 logarithm of 32
);
console.log(
Math.max(7, 42, 1) // Maximum value among all arguments
);
console.log(
Math.sqrt(16) // Square root of 16
);

As a coder, you will be writing a lot of functions. So let’s learn how to do that.

Defining Functions

The syntax to define a function in JavaScript is to use the keyword function and give the function a name. For example:

function add(arg1, arg2) {
// Do a transformation on arg1 and arg2
// Then return a value
}

I named the function add and made it receive two inputs: arg1 and arg2.

“Arg” is short for argument. A function can have zero or more arguments. Inside the function body, which we created using the curly braces, we will have access to arg1 and arg2 once that function is called. For example, we can call the function add using this syntax:

add(10, 5);

The line of code above means: execute the body of the function add and assign the value 10 to arg1 and the value 5 to arg2.

Inside the function’s body, we continue writing our program text line by line. In the example above, I used comments inside the body. These comments are ignored by the computer and are there for the human eye only. Any line that begins with // is a comment line in JavaScript. Different computer languages will have different syntaxes for these concepts, but the idea is the same.

In JavaScript, you can also do multi-line comments using the /* … */ syntax:

/*
All this text
will simply be
ignored by the computer
*/

Let’s now replace the comments with something the computer can do. Here is an example implementation of the function add:

function add (arg1, arg2) {

let result = arg1 + arg2;
return result;


}

Every time the add function is called the computer will reserve a memory space and label it as result. It will then evaluate the expression arg1 + arg2 using the values we pass as arguments to the add function when we call it. It will then place the result of that operation in the memory space that is labeled result.

The line that follows begins with a return keyword. What’s expressed after a return keyword is what the output of this function will be. In this example, the function reads the memory space labeled result and returns that value as the output.

How do we test this function? A function call is also an expression, which means we can use that output as the value for another variable. For example:

let output = add(10, 5);

console.log(output);

The function add allowed us to abstract the addition operation into its own entity instead of doing that operation directly like the example we started with. This is a useful concept in programming for many reasons, but most importantly because of the following:

  • Many programs can now call the same add function.
  • If someone else manages the add function, we do not have to worry about what is going on inside it. We can just use the function to get the expected behavior. The owner of the add function might later decide to use a different implementation to perform the addition operation, and in that case our program — the one that used the function — would not be affected.
  • The owner of the add function can test that function in isolation of the code that actually uses the function.

Functions are very useful. Whenever we want to make code generic and reusable, we can abstract that code into a function and call that function instead.

Practice Challenges

Challenge #1 — Write a function “multiply” that takes three arguments and multiplies them together.

Here is an example of the expected output:

multiply(1, 2, 3); // should return 6
multiply(10, 10, 10); // should return 1000

Starting Template: jscomplete.com/playground/SkrzLayYZ

Solution: jscomplete.com/playground/Hyd2XEGYZ

Challenge #2 — Write a function that will calculate the area of a triangle given base and height measurements.

Here is an example of the expected output:

triangleArea({ base: 15, height: 4 })  // should return 30
triangleArea({ base: 6, height: 9 }) // should return 27

Hints:

  • The triangleArea function will receive one argument that will be an object. That object will have two properties: base and height.
  • You can use the dot notation to access these properties inside the function’s body.

Starting Template: jscomplete.com/playground/HyK4zVzFW

Solution: jscomplete.com/playground/r1VEmNztZ

Chapter 2: The Basic Syntax Overview

In the previous chapter, you were introduced to some basic-level concepts of expressions, variables, objects, and functions. Let’s now do a deeper dive into these concepts and bring in a few new ones. All concepts are simple, but some of them depend on logic/math knowledge.

Statements and Expressions

We have seen a simple expression in the previous chapter; it was:

5 + 2

An expression is a section in code that produces a value. You can think of this as the relation between:

  • One Oxygen atom mixed with two Hydrogen atoms (expression)
  • One Water molecule (value)
// The expression
1 Oxygen atom + 2 Hydrogen atoms

// The value
1 Water molecule

We can use expressions (values) in many places. You will usually see them on the right-hand side (RHS) of the assignment operator =:

someVar = someExpression;

Warning: I’ll use the abbreviations RHS and LHS (left-hand side) from now on.

There is another syntax category in JavaScript that we call statements. Statements are not expressions because they do not produce values. They just perform tasks like defining variables, creating logic branches, or repeating other statements. Here is an example statement:

let sum;

This statement just creates the variable sum in memory. It does not evaluate to anything beyond that. In fact, we cannot use a statement on the RHS of an assignment operator. For example, we cannot do this:

someVar = let sum; // Error!

The details about what can go on the LHS and RHS of an assignment operator might be boring, but it is an essential thing to understand. For now, remember that anything that you can use on the RHS of an assignment operator is an expression (or value, eventually) and anything you cannot use on the RHS of an assignment operator is a statement.

Values and Keywords

Every value has a type. For example, a value can be a number, character, or string of characters forming words and sentences:

// Example of values

42 // Number value
'A' // One Character
'Hello' // String

Note how the character and string above are surrounded by single quotes. You can also use double quotes if you prefer. These quotes are not optional for strings in programming because without them the computer will think what you wrote is a keyword or a variable.

A keyword is a word with a special meaning. For example, we have seen the keyword let which means define a variable. Because it is a keyword, the computer will always perform what it means when parsing a program. If you write the sentence “let me understand this” somewhere in code without using quotes, you will get an error:

let me understand this // will give an error

This is because the computer is trying to define a variable me and the rest of that line is invalid syntax (after “let me”, the computer expects a semicolon, a comma, or an = operator. We gave it an unexpected identifier!)

However, if we surround the sentence with single or double quotes, the word let becomes part of that string (and stops being the usual keyword).

'let me understand this' // valid syntax

Some of the popular keywords in JavaScript include: let, const, if, else, switch, try, catch, return, true, false, class, function, for, and this. You can see the full list on the MDN website.

You cannot use keywords as names for variables. The following will throw an error:

let function = 5 + 2; // Error

When the computer sees the word function it wants to define a function, so the use of the token function after the token let was unexpected.

But even if we are not using keywords in our sentences, the computer will try to lookup any unquoted word as either a keyword or a variable and it will complain if it cannot find it.

what // Error

We started a line with an unquoted what which is not a keyword, so the computer looks it up as a variable and complains that: what is not defined.

Boolean Values

One of the most common types of values in programming is the Boolean type. It is the type that determines if an expression is true or false. This type is used in conditional statements (which are explained later in this chapter).

The Boolean type has two explicit values: true and false. It also has many other implicit values. Every other type in JavaScript can be converted to a Boolean. JavaScript does a lot of auto-conversion between types.

For now, just know that ALL values in JavaScript are also considered true except this short list: undefined, null, 0, "", NaN, and false itself.

In fact, JavaScript has a Boolean function that can explicitly convert values to their Boolean equivalent. You can use it to see how the five special values above are all converted as false while everything else is true:

Boolean('')        // false
Boolean(0) // false
Boolean(undefined) // false
Boolean(null) // false
Boolean(NaN) // false

Boolean(1) // true
Boolean('Hello') // true
Boolean(Math.PI) // true
Boolean(Boolean) // true

The special NaN value means Not-A-Number. No Joke. For example, in Mathematics, there is no number that can represent the square root of -1. That is why in JavaScript Math.sqrt(-1) will equal NaN.

You can also get a NaN in many other situations. For example, try to divide a string by a number.

A JavaScript joke:

if (typeof bread == NaN) { return toServer; }

The null and undefined Values

The keywords null and undefined are two special keywords in JavaScript that you need to understand right now. They represent a similar concept: the absence of value.

The following quote is going to be confusing:

null and undefined are both values that represent the absence of values

Weird. I know.

Let me tell you the story of a variable x.

A variable x starts by being undeclared (note how I did not use the term undefined yet). When we use the let keyword, we declare a variable.

let x;

Now x is declared, but it is now undefined. The value inside x is still “undefined”, but x itself, as a reference to a space in memory, is declared. That space in memory does not have a value.

When we put a value in x, we define x.

x = 42;

With that, x is now defined. It has the defined value of 42.

We can revert x to not be defined — if we need to — using the special undefined value:

x = undefined;

Or using the null value:

x = null;

Most other programming languages have only one type to represent the absence of a value. However, for many reasons, mostly historical ones, JavaScript has two types. Sometimes, that is actually helpful. We can use undefined to represent the unexpected and system-level absence of a value and use null to represent the normal and program-level absence of a value. For example, consider this object:

let obj = {
a: 1,
b: null,
};

We have three types of properties:

  • The obj.a property is defined and holds the value 1
  • The obj.b property is defined but has no value (it is intentional)
  • The obj.c property is undefined (it is not an expected property)

Basically, if you want to check whether a certain object property is defined but empty or not defined at all, null and undefined can be used for that purpose.

Arrays

We have seen a few objects so far. An object is a special value type that holds a collection of other value types and each value gets a unique identifier (object property).

There is one other special value type that can hold a collection of other value types. It is called the Array type.

Just like objects, arrays hold a collection of other values but the identifiers that arrays use for those values are just their positional order, which starts with 0 for the first element.

Counting from 0 is weird, but you need to get used to it. The Xth element has an index value of X -1(for example, the 8th element has an index value of 7).

We create arrays and access their elements using the square brackets []. Here is an example array that holds four different numeric values:

let primesUnder10 = [2, 3, 5, 7];

The identifier for the first prime number is its position in the array: 0, and so on:

// Position   // Value
0 2
1 3
2 5
3 7

We can access individual values using their positions:

primesUnder10[0] // 2
primesUnder10[2] // 5

The array[position] syntax is an example of an expression that produces a value. Anywhere we can use a value, we can use that syntax as well. For example, I can sum the first three prime numbers using this expression:

primesUnder10[0] + primesUnder10[1] + primesUnder10[2] // 10

Arrays can hold other value types as well:

let hello = ['h', 'e', 'l', 'l', 'o'];

And they can hold different value types, including objects, arrays, and even functions:

let mix = [1, true, undefined, {}, [], function x() {}];

The last value in the mix array above is a dummy function (one that does nothing). I can call that function directly from its position in the array: mix[5](). We were able to use a function as an element in this mix array because functions are also values.

There are a few other special types in JavaScript that can be used to represent a collection, including Map and Set. Let’s talk about those.

Maps and Sets

A map object in JavaScript is another way to represent a list of key-value pairs. It is very similar to the plain-old JavaScript object, but it offers a bit more features on a collection such as reading the size of the collection and iterating over its items. Maps will also guarantee the order of records they contain which make them a safer bet when you need to manage a collection of records.

Here is how you can create a new map object:

const days = new Map();

To set a new property (key) on this days map, we can use the .set method:

days.set(0, 'Sunday');
days.set(1, 'Monday');
// ...
days.set(6, 'Saturday');

To read a value using its key, we can use the .get method:

console.log('Today is', days.get(new Date().getDay()));

You can also do things like checking if a key exists in a map:

days.has(7) // false

A set object in JavaScript is another way to represent a list of values just like arrays. However, unlike an array, a set object can only store unique values. You cannot store duplicate values with sets and that makes them very useful in certain cases. For example to manage the list of days in a week.

const days = new Set();

set.add('Sunday');
set.add('Monday');
// ...
set.add('Saturday');

To access these unique days, you will have to loop over the list. We cover loops in the next chapter.

Classes

A class is simply a blueprint or a template that we can use to generate different objects that share some shape and/or behavior. If you want to build something complicated, you always start with blueprints. This is what classes are for in programming.

We use classes to create objects. All objects created from the same class can share some attributes. Most importantly, they share behavior.

All objects we have seen before were created from built-in classes. Classes in JavaScript begin with a capital-letter. JavaScript has classes like Number, String, Object, and Array. You all also learned about two other classes in the previous section: Map and Set.

To create an object from the Map class, we used the new keyword:

const days = new Map();

A class can be used to define object-level state and behavior to be shared among all objects. In JavaScript, we can manipulate an object’s state within its class using the “this” keyword and we can define shared behavior with class functions. Functions that belong to a class are usually referred to as methods.

When you program with objects, a class definition always comes first. We have been working with objects so far because we have been working with built-in classes. However, JavaScript offers a way for you to create a custom class. Let’s create a class to represent a bank account:

class Account {  constructor(id) {
this.id = id;
this.balance = 0;
this.createAt = new Date();
}

deposit = (amount) => {
this.balance = this.blanace + amount;
};

withdraw = (amount) => {
this.balance = this.balance — amount;
};

printBalance = () => // Just for testing...
console.log(‘Balance is: ‘ + this.balance);
}

We can then start managing individual bank accounts using objects:

const accountA = new Account('A');
const accountB = new Account('B');

accountA.deposit(42);
accountB.deposit(420);

accountA.withdraw(10);
accountB.withdraw(10);

accountA.printBalance(); // Balance is: 32
accountB.printBalance(); // Balance is: 410

The process of creating objects from a class has its own fancy name: instantiation. This is why class objects are often referred to as instances.

We can also base a new class on an existing class. We call that concept in programming inheritance. A child class can inherit from a parent class!

In JavaScript, we can do that using the extends keyword:

class CheckingAccount extends Account {
constructor(id) {
super(id);
this.type = 'checking';
}

// ... Methods specific to checking accounts

}

The above code means that a checking account object will automatically have the state and behavior of a basic account object (like id, balance, createdAt, deposit, and withdraw) but it will also have the other state and data defined in the CheckingAccount class.

It is okay to use one-level of class inheritance in your applications, but try to avoid using multiple levels as that tends to make the code less clear.

Operators

Operators are special characters (or words in some cases) that can be used between two operands (which are basically values) to perform an operation. The 2-values operators are actually categorized as binary operators. In the next two sections, you will see an example of a unary operator (!), which works on a single operand, and a ternary operator (? :), which works on three operands.

You have seen examples of binary operators like the assignment (=), addition (+), multiplication (*), division (/), and subtraction (-) operators, but there are more. For example, two other popular binary operators are the logical operators && and ||.

The && operator sits between two values (or expressions) and performs the AND logic gate. The || operator performs the OR logic gate. Each of them has four possible outcomes:

true && true   // true
true && false // false
false && true // false
false && false // false

false || false // false
true || true // true
true || false // true
false || true // true

You actually need to memorize this table. If you remember the bolded unique case in each section you will remember the rest.

You can imagine how each true/false value above can also be an actual value because the && and || operators will do type conversion:

0 && anything 
// Equivalent to false because Boolean(0) is false

42 || anything
// Equivalent to true because Boolean(42) is true

Of course, the result of any operation is also a value, which means we can combine operator calls together to do more complex operations. Try to figure out the result of these combined operations:

2 * 10 + 22

true && true || false

(3 * Math.PI + Math.PI) / Math.PI

Other commonly used binary operators are the greater than (>), less than (<), and the equality operators described next.

Strict and Loose Equality Operators

JavaScript has many operators that we can use to compare values. They all produce either true or false based on their operands’ equality.

There is the loose equality operator, ==, which should generally be avoided (because, well, someone named it loose!):

3 == 3    // true.

3 == '3' // Also true.
3 == 4 // false

As you can see, the loose equality operator also does a implicit type conversion and does not care about the different operand value types.

On the other hand, the strict equality operator (===) compares two values for equality without any implicit type conversions:

3 === 3        // Sure3 === '3'      // No3 === (1 + 2)  // true

Of course, there are also loose and strict inequality operators (!= and !==).

By the way, the character ! (on its own) is used as a prefix logical operator that means NOT. It is an example of a unary operator that operates on a single value.

!true  // false

!0 // true

The Famous if-statement

One statement that is very popular in programming languages is the if-statement. You have probably heard of it or have seen a few examples.

Here is the official syntax of an if-statement in JavaScript:

if (expression) {
statementA1;
statementA2;
// ...
} else {
statementB1;
statementB2;
// ...
}

The else part is optional, but it will help you understand the if part.

We know what an expression is and we know what a statement is. However, a more accurate syntax description for an if-statement would describe the expression as a condition: something that is either true or false.

Remember that everything in JavaScript is either true or false. The if-statement’s expression value is no exception.

The if-statement above will first convert the expression in parentheses to a Boolean value. If that Boolean value is true, it will execute statementA1, statementA2, … and it will not execute statementB1, statementB2, … If the Boolean value is false, it will do the exact opposite.

The if-statement is popular because it enables conditional logic. It offers a way to execute certain code only when a certain condition applies. This is also often referred to as conditional branching. For example, let’s assume that we want a function that doubles the value of its single argument only when that argument is an odd number. The function should not double the value for even numbers. This function can be easily written with an if-statement:

function doubleOddOnly(number) {
if (number % 2 === 1) {
return 2 * number;
}

return number;
}

// Try it with
doubleOddOnly(3);
doubleOddOnly(10);

We were able to check the oddity of a number using the modulus math operator (%), which gives the remainder of a division operation:

5 % 2   // 1

6 % 2 // 0

11 % 3 // 2

If the remainder when dividing the number by 2 equals to 1 (a Boolean expression that uses the strict equality operator), the doubleOddOnly function will return the number argument multiplied by 2. Otherwise, it will return the number argument as is.

Note that we did not need to use an else section for that if statement because we used return statements. A return statement is the last statement executed in a function. When the function executes a return statement it will not execute the rest of the code that follows that return statement. This is why the second return statement is equivalent to having an else section for the if statement.

The reason an if-statement is named a statement is that it does not evaluate to anything. It only does its conditional picking of other statements. For example, we cannot use an if-statement on the RHS of the assignment operator:

let result = if (3 == '3') { 42 } else { 0 };  
// Syntax Error

While writing the whole if-statement on one line is okay (spaces and new lines, in general, are ignored by the computer), the fact that we used that line on the RHS of the assignment will give an unexpected token error.

Other languages (like Ruby for example) treat the if-statement as an expression as well, but In JavaScript an if-statement is just a statement.

There is another syntax that we can use to do the conditional if-logic within an expression. It is called the ternary operator (because it operates on three operands). To do so, we need to use two different characters (? and :):

condition ? if-true-value : if-false-value

Since this is an expression, it will produce the if-true-value if the condition part is true, and the if-false-value if the condition part is false.

The problematic one-line if-statement example above can be easily and correctly written using the ternary operator:

let result = (3 == '3') ? 42 : 0; // No problem

What is the value of result above, by the way?

Practice Challenges

Challenge #1 — Write a function that will determine if a number is odd or even.

Examples of expected output:

oddOrEven(17) // should return 'odd';

oddOrEven(100) // should return 'even';

oddOrEven(5 + 4) // should return 'odd';

Starting Template: jscomplete.com/playground/H1HDhfqK-

Solution: jscomplete.com/playground/SkErP5TKZ

Challenge #2 — Determine the output of the following code:

function mystery(arg1, arg2) {
if (arg1 && arg2) {
return 'Hello';
}

return (arg2 % 3 === 1) ? 'World' : ', ';
}

mystery(null, 10) + mystery(true, 0) + mystery(10, 'null');

Do not copy/paste the code to evaluate it and do not guess. Parse the code line-by-line and follow what it does.

Solution: jscomplete.com/playground/HysDDcptW

Chapter 3: Scopes and Loops

In the two previous chapters, you were introduced to concepts like statements, expressions, values, keywords, arrays, objects, functions, and if-statements. This chapter will introduce two new concepts: Scopes and Loops.

To understand scopes, we first need to understand variables.

Variables

We can declare variables in JavaScript in many ways:

// Good
let varName = 'someValue';

// Better!
const varName = 'someValue';

// Avoid this one (explained later in the chapter)
var varName = 'someValue';

Variables are used to represent many things, but they are famously known to hold what we call state. State is basically data that can be changed during the lifetime of an application.

In some programming languages, when we declare variables we also declare the type of data these variables are supposed to hold. Would the variable hold an integer or a string? Or an array of integers? This decreases the flexibility of what you can do with the variable, but it also decreases the possibility of using the variable incorrectly (among many other benefits).

For example, in C++ you would see code like this:

int num;

bool isPrime = true;

The int and bool keywords are equivalent to JavaScript’s let keyword, except they define variables that can only hold certain types. The variable num can only hold integers and the variable isPrime can only hold Boolean values. This is enforced by the language, so if you use the wrong data type with that variable you get an error (before you even run the program).

JavaScript does not do type checking like this. Variables declared with JavaScript can have any type of data:

let mystery;

mystery = 'Hello';

mystery = 42;

mystery = false;

mystery = [2, 3, 5, 7];

mystery = function x () {};

mystery = {};

// All ok

let vs. const

The difference between let and const is an important one to understand.

Using the keyword const creates a constant reference for the variable. We cannot change the value of a constant reference. If we put a primitive value in a constant, that value will be protected from getting changed:

const PI = 3.141592653589793;

PI = 42; // SyntaxError: "PI" is read-only

Note that if the constant is an object we can still change the properties of that object, so be careful about that:

const dessert = { type: 'pie' };

dessert.type = 'pudding'; // Sure thing

console.log(dessert.type); // pudding

However, we cannot re-assign an object declared with const:

const dessert = { type: 'pie' };

dessert = { type: 'cake' };
// SyntaxError: "dessert" is read-only

Since const is protecting a reference to something, when using the const keyword to declare a variable we must specify that variable’s value (while with let we can omit the initial value). You simply cannot declare an empty variable with const:

const xyz; 
// SyntaxError: Missing initializer in const declaration

let xyz;
// Sure, No Problem. xyz is now declared but undefined.

Constants are popularly used when importing modules from other libraries so that they are not accidentally changed. Constants are also great to use when defining functions because we rarely need to update a function after we define it the first time.

In general, I think it is good to always use const for your declarations and only switch to let if you absolutely need to. With const, you get the peace of mind that no mutating reassignments are happening on a variable, while with let you will have to read the code to verify that:

let answer = 42;

// some code ...

// answer MIGHT be 42 here, read the code to be sure.

Vs.

const answer = 42;

// some code ...

// answer IS STILL 42 here, no matter what happens above

The difference between let/const and var is good to understand so that you avoid using the var keyword because, well, it is weird. However, to understand that difference we need to understand the concept of scopes.

Scopes

A scope in JavaScript is a section in the code that can have its own private variables.

The simplest scope can be created using the curly braces syntax: {}.

Here is an example scope that defines the variable answer. If you attempt to access that variable outside of that scope, you get an error:

{
let answer = 42;
}

console.log(answer); // ReferenceError: answer is not defined

We call scopes that are created using just the curly braces block scopes. You have seen an example of block scopes when we talked about if-statements.

Every if-statement gets its own block scope:

if (condition) {
// block scope
}

Another famous statement that gets its own block scope is the for-statement (explained later in this chapter).

Block scopes can be nested:

{
let a = 1;

{
let b = 2;
}

// You cannot access b here, but a is ok
}

// You cannot access a or b here.

Do not confuse block scopes with empty object literals. The curly braces syntax can also be used to define objects:

let a = {}; // empty object literal

{ let a; } // undefined object in a block scope

if (3 == '3') {
// block scope for the if-statement
}

There is another type of scope: function scopes.

A function scope is created for every function we invoke (and they can be nested too):

function iHaveScope() {
// local function scope

function iHaveNestedScope() {
// nested local function scope
}
}

We often identify function and block scopes as local scopes and identify the top-level scope as the global scope. When you define a variable in JavaScript that is not in any scope, you will be using the global scope. Try to avoid doing that.

In reality, it is hard to completely avoid the global scope, but you should minimize the use of any global variables because they represent a state and having that defined globally makes it more vulnerable to conflicts and data corruption.

Since every function gets its own scope, we can wrap any code in a function to force it to not use the global scope. Then, we can simply invoke the function right away because otherwise the wrapped code would not be executed. This is a common pattern in JavaScript that is called: Immediately Invoked Function Expression (IIFE):

(function() {
// your code here
})();

Note how to accomplish this we needed to wrap the function in parentheses and then call the wrapped function.

The var keyword behaves differently in function scopes and block scopes. A variable declared with var in a function scope cannot be accessed outside that function scope:

function iHaveScope() {
var secret = 42;
}

secret; // ReferenceError: secret is not defined (in this scope)

A variable declared with var in a block scope is available outside of that block scope. This is the weird part:

if (true) {
var i = 42;
}

console.log(i); // 42

The i variable that we used in the if-statement above will continue to exist beyond the scope of that statement. This does not really make sense and it is the reason why this chapter began with the advice of completely avoiding the var keyword. Just use const if you do not need to change the reference to the created variable (most cases) and use let if you do (some cases).

Loops

Sometimes you need to repeat actions and computers are very good at that. If you try to punish a computer into writing the phrase “I will not freeze unexpectedly” 20 times, it can do that in milliseconds. All it needs is what programmers call a loop.

A loop can be written in many ways. The most common form of a loop is the for-statement. Below is the for-statement that a computer can use to write the punishment phrase 20 times:

for (let i = 0; i < 20; i++) {
console.log('I will not freeze unexpectedly');
}

While the for-statement above might be easy to understand, in order to be able to write for-statements yourself you should understand the three sections that I used above inside the for-statement parentheses. These sections are separated by semicolons.

Here are some labels we can give to these sections:

for (
do-once-before-everything; // 1st
check-condition-before-every-iteration; // 2nd
do-after-every-iteration // 3rd
) {
// A single iteration statements
}

We call the body of the for-statement an iteration. A for-statement will do zero or more iterations based on the three sections in its parentheses.

The for-statement also gets its own block scope. All variables we declare with let and const inside a for-statement (including inside its parentheses) are only accessible within that for-statement.

Before the first iteration, the for-statement executes the first section in its parentheses. It will do that just once (not before every iteration). In the example above, we declared the variable i (representing an index) and set its initial value to 0. We can initialize many variables if we need to inside this first section. We can also omit this section if we want the for-statement to use other variables that already exist in its parent scope.

Now that we have the index variable set to 0, the for-statement will attempt its first iteration. Before that iteration (and every other iteration), it will check if the condition expression that we supply in the second section is true. If it is true, the iteration will be carried out. If that condition is false, the for-statement will be done, and the computer will continue to execute whatever is after the for-statement.

After every iteration is done, the for-statement executes the third section in its parentheses. Usually, this section is used to increment (or decrement) the loop’s index.

I used the increment operator (++) to do that because it is commonly used in that section. The increment operator is equivalent to adding 1 to its operand. The following three expressions all add 1 to i:

let i = 0;

i++; // i is now 1

i = i + 1; // i is now 2

i+=1; // i is now 3

The last expression uses what we call a compound assignment. It is a special syntax for the assignment operator that is combined with the + operator (two birds with one stone). The compound assignment/plus operator will do the plus operation first and then assign the new value to its operand. Just like +=, there is also *=, -=, and /=. Not all operators can be combined in JavaScript. For example, you cannot do &&= or ||= (although other languages allow that).

It is usually a good idea to avoid increment operators ++ (and decrement operators --) when possible because they tend to make the code less readable. However, they are fine in a for-statement.

While the third for-statement section can be used for this purpose, nothing prevents us from using something similar to the last statement inside the for-statement body.

The example above can be written without using the first or third section of the for-statement this way:

let i=0;

for (;i < 20;) {
console.log('I will not freeze unexpectedly');
i++;
}

Note how I left the first and third sections above empty. We can do that.

A Practical Example for-loop

Being able to execute the same group of statements many times is neat, but what is a practical example for that?

If I ask you to sum all the numbers under 100, basically 1 + 2 + 3 + 4 + … + 99, how would you do that?

If you like math, you might immediately say: there is a formula for that.

There is, but what if you do not know that formula and all you can use is JavaScript? A loop would do that. Loop exactly 99 times and add the loop index to a running sum. Do you think you can attempt that on your own first? (the answer is 100*99/2, or 4950).

Here is one loop you can use to calculate that sum:

let sum = 0;

for (let i = 99; i > 0; i — ) {
sum += i;
}

console.log(sum);

Note how I made the loop index start from 99 and go all the way down to 0. I also used the decrement operator in the third for-statement section.

Also note how I maintained the sum variable inside the parent scope of the for-statement so I can access it inside and outside the for-statement.

The iteration that was repeated 99 times simply adds the loop index to the sum variable each time, resulting in 99 + 98 + 97 + … + 1.

break/continue

Sometimes it is useful to skip one iteration while executing a for-statement. We can use the continue keyword to do so.

Other times it is useful to finish the for-statement early, before its condition turns into false. We can use the break keyword to do so.

The break/continue keywords are usually used with an if-statement inside a loop. While the loop statement is doing its iterations, if a certain condition is true you can either use continue to skip the current iteration or break to exit out of the whole loop.

Examples:

1 — Write code to repeat the 99 numbers sum example above but only include numbers that are divisible by 2 and 3. So 6 and 12 should be counted but 5 and 20 should not.

Can you try to do that on your own first? (the answer is 816).

Here is one way to solve this challenge:

let sum = 0;

for (let i = 99; i > 0; i--) {
if (i % 2 !== 0 || i % 3 !== 0) {
continue;
}

sum += i;
}

console.log(sum);

Note how I used a condition to skip every iteration when the number is not divisible by 2 and 3. This is not the only way to solve this problem and it is certainly not the most efficient way to do so. Usually, we use continue and break when the condition that controls them is unknown.

For example, we can use them when the condition depends on some sort of user input.

The easiest way to take input from the user in a browser environment is to use the special prompt function. It will show a prompt and ask the user to type something. Whatever the user types will be captured as the return value of the function. Here is an example:

const answer = prompt('What is your answer?');

console.log('Your answer was', answer);

Note how console.log can have multiple arguments!

2 — Write code to keep prompting the user for an answer until they enter the right answer, 42! Note that “prompt” always return a string.

for(let answer;;) {
answer = prompt('What is your answer?');

if (answer === '42') {
break;
}
}

Note how I only used the first section of the for-statement to declare an answer variable (I did not need to initialize it). I did not need the other two sections because I used a break statement to determine when to exit from the loop.

This loop can run for an infinite amount of iterations until the user types in 42.

If a loop has no way to exit at all, we call it an infinite loop. Infinite loops will just keep running until they freeze your computer by using all its resources.

Here is the simplest infinite loop (do not execute this code):

for (;;) {}

There is no initialization, condition, or increment. It just runs forever. You will probably never need to use an infinite loop. Just be aware that you can accidentally run into them.

for…in and for…of

The good old for-statement has two cousins. A for…in statement and a for…of statement. These are special forms that are designed to work with variables that represent collections like arrays, objects, or maps.

The for…in statement is weird and might surprise you, so I recommend that you completely avoid using it. The for…of statement, on the other hand, is not weird at all. Here is an example of how you can use it to iterate over an array:

const primesArr = [2, 3, 5, 7];

let sum = 0;

for (let prime of primesArr) {
sum += prime;
}

console.log(sum); // 17

Compare that to what you would need to do in order to write the exact same example with a regular for-statement:

const primesArr = [2, 3, 5, 7];

let sum = 0;

for (let i = 0; i < primesArr.length; i++) {
sum += primesArr[i];
}

console.log(sum); // 17

The bolded parts above are what is different. Clearly, the for…of statement makes this task much easier. With for…of you do not need to manually manage a loop index.

while and do-while

There are two more statements that we can use to create a loop.

There is the while-statement, which is basically a for-statement without the first and third section:

while (check-condition-before-every-iteration) {
// A single iteration statements here…
}

I prefer while-statements over for-statements because I find them to be more readable. We do not need to rely on a weird structure (first, second, third) to write them. They are much closer to how we describe things in English.

In English:

Keep sleeping while it is dark outside.

In JavaScript:

while (isDarkOutside) {
keepSleeping();
}

Anything you can do with a for-statement you can do with a while-statement as well. Here is the 99-sum example written with while:

let sum = 0;
let i = 99;

while (i > 0) {
sum += i;
i -= 1;
}

console.log(sum);

Admittedly, this solution has a bit more lines of code than the one we did with a for-statement, but I find it to be easier to parse with the human eye.

My recommendation is to understand the for-statement structure but use the while-statement when you need simple loops.

Some loops have the special need of being evaluated at least once. In such loops, the iteration statements are to be executed before checking the loop condition. A perfect example of this is the prompt example that we used above. We KNOW that we need to read the user’s answer at least once.

We can use a do…while statement to create such loops. Here is the prompt example written with do…while:

let answer;

do {
answer = prompt('What is your answer?');
} while (answer !== '42');

I find this to be a lot more readable than using a for-statement with empty sections. It is very clear. It does what is in the body of the statement at least once and then starts checking the while condition. It then keeps re-doing what is in the body of the statement while the condition is true.

Practice Challenges

Do the following exercises right now. There are easy!

1 — Figure out the output of the following code:

{
let a = 1, b = 2, c = 3;
{
let b = 10;
{
c = 20;
}
}
console.log( a + b + c );
}

Solution: jscomplete.com/playground/SJ3fLE7cW

2 — Given an array of printable ASCII numbers in decimal, write a function to convert that array into a string.

For example, use a space in the string when the number is 32, A when it is 65, and Z when it is 90. Examples of expected output:

asciiArrToString([72, 101, 108, 108, 111, 33]); 
// "Hello!

asciiArrToString([52, 50]);
// "42"

Hints:

  • You can use the function String.fromCharCode to convert a single ASCII number into its corresponding printable characters.
  • You need a loop.

Starting Template: jscomplete.com/playground/H1CsJHQ9b

Solution: jscomplete.com/playground/HkxbkB75b

--

--

Samer Buna
EdgeCoders

Author for Pluralsight, O'Reilly, Manning, and LinkedIn Learning. Curator of jsComplete.com