The Basic Syntax Overview
This chapter covers
-
Statement and expressions -
Statements and Expressions
We have seen an expression in a previous article; 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 do things. 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 there 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. Those quotes are not optional for strings in programming because without them the computer is going to 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
. It means define a variable. What if I want to 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 not 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 here.
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 article).
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.
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 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 value1
-
The
obj.b
property is defined but has no value (it is intentional) -
The
obj.c
property isundefined
(it is not an expected property)
So, 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
.
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. These include reading the size of the collection and iterating over its items. Maps are usually 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 exist 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 upcoming articles.
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();
Beside the name, a class can be used to defined object-level state and behavior to be shared among all objects. In JavaScript, we can maniple an object’s state within its class using the “this” keyword and we define shared behavior with class functions. Functions that belong to a class are usually referred to as methods.
The class 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 probably okay for you 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 we can use 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 the implicit type conversion thing 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 conversations:
3 === 3 // Sure 3 === '3' // No 3 === (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 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 parenthesis to a Boolean value. If that Boolean value is true, it will execute statementA1
, statementA2
, …etc and it will not execute statementB1
, statementB2
, …etc. If the Boolean value is false, it will do the exact opposite.
The if-statement is popular because it enables conditional logic. It enables us to execute certain code only when a certain condition applies. 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
is 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 after that. That is why the second return
statement is equivalent to having an else
section for the if
statement.
I included a section about the if-statement here because it is an example of a statement! An if-statement 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 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
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