Learn JavaScript: Novice to Ninja

Chapter 2: Programming Basics

In the last chapter, we introduced JavaScript, then set up a programming environment. We even got our hands dirty with a few JavaScript programs. In this chapter, we’ll delve further and learn how JavaScript works, as well as write some more programs.

This chapter will cover the following topics:

  • The importance of well-commented code
  • JavaScript grammar ― expressions, statements, semicolons and whitespace
  • Primitive data types
  • Strings ― string literals, string properties and methods
  • Declaring and assigning constants and variables
  • Numbers ― decimal, hexadecimal, octal, binary and exponent form, Infinity, and NaN
  • Arithmetic operations such as +, -, *, /, and %
  • Undefined and null
  • Booleans ― truthy and falsy values
  • Logical operators ― AND, OR, and NOT
  • Our project ― we’ll set some question-and-answer variables and use alert boxes to display them

Comments

Our first task on our journey to becoming a JavaScript ninja is learning how to write comments in JavaScript. This may seem a strange place to start, because in programming, a comment is a piece of code that is ignored by the language ― it doesn’t do anything. Despite this, comments are extremely important: well-commented code is the hallmark of a ninja programmer. It makes it easier for anybody reading your code to understand what’s going on, and that includes you! Believe me, you’ll be thankful you commented your code when you come back to read it after a few weeks. You don’t need to write an essay though, just enough so that it’s clear what the code is supposed to do.

In JavaScript there are two types of comment:

  • Single line comments starting with // and finishing at the end of the line:// this is a short comment
  • Multi-line comments starting with /* and finishing with */ :/* This is a longer commentanything here will be ignoredThis is a useful place to put notes*/

It’s good practice to write comments in your code. There are even utilities that can take your comments and produce documentation from them such asJSDoc Toolkit,Docco, andYUIDoc. You’ll see lots of comments throughout the code in this book.

JavaScript Grammar

The syntax used by JavaScript is known as a C-style syntax because of its similarities with theC programming language.

A JavaScript program is made up of a series of statements. Each statement ends with a new line or semicolon.

Here is an example of two statements, one on each line:

const message = 'Hello World!'alert(message)

This example could also be written as follows, using semicolons at the end of each statement:

const message = 'Hello World!';alert(message);

There’s no need to actually use a semicolon to terminate a statement because JavaScript interpreters use a process called Automatic Semicolon Insertion (ASI). This will attempt to place semicolons at the end of lines for you. However, it can be error-prone and cause a number of automated services such as code minifiers and validators to not work properly.

For this reason, it’s considered best practice to combine the two and write each statement on a new line, terminated by a semi-colon, like so:

const message = 'Hello World!';alert(message);

A block is a series of statements that are collected together inside curly braces:

{// this is a block containing 2 statements    const message = 'Hello!';    alert(message);}

Blocks do not need to be terminated by a semicolon.

Whitespace (such as spaces, tabs and new lines) is used to separate the different parts of each statement. You can use as much whitespace as required to format your code so it’s neat and easy to read. Examples of this include using spaces to indent nested code and multiple lines to separate blocks of code.

Reserved Words

The following words arereservedfor use by the JavaScript language and cannot be used to name variables (or function parameters and object properties that appear in later chapters):

abstract, await, boolean, break, byte, case, catch, char, class, const, continue, debugger, default, delete, do, double, else, enum, export, extends, false, final, finally, float, for, function, goto, if, implements, import, in instanceof, int, interface, let, long, native, new, null, package, private, protected, public, return, short, static, super, switch, synchronized, this, throw, throws, transient, true, try, typeof, var, volatile, void, while, with, yield

These words are reserved because many of them are used by the language itself, and you will come across them later in this book.

Some of the reserved words are not used by the language, however; one can only assume they were planned to be used at some point, but never were. There are also a few wordsnotreserved but really should have been, as they are an important part of the language:

undefined, NaN, Infinity

These are covered later in this chapter and should be treated as if they were reserved words and avoided when naming variables, despite the fact that JavaScript may let you do it.

Primitive Data Types

JavaScript has seven different data types. Six of them areprimitive data typesand are listed below:

  • String
  • Symbol (The symbol primitive data type was only introduced in ES6.)
  • Number
  • Boolean
  • Undefined
  • Null

Any value that isn’t one of the primitive data types listed above is anobject. These include arrays, functions and object literals, which will be discussed in later chapters.

JavaScript has a special operator called typeof for finding out the type of a value.

Here are some examples of the different value types:

typeof 'hello'<< 'string'typeof 10<< 'number'typeof true<< 'boolean'typeof { ninja: 'turtle' }<< 'object'typeof [ 1, 2, 3 ]<< 'object' (All non-primitive data types return a type of 'object'.)

An operator applies an operation to a value, which is known as theoperand. A unary operator only requires one operand; for example:

typeof 'hello'

The operator is typeof and the string ‘hello’ is the operand.

A binary operator requires two operands; for instance:

3 + 5

The operator is + and the numbers 3 and 5 are the operands.

There is also a ternary operator that requires three operands, which is covered in the next chapter.

Variables

Variables are used in programming languages to refer to a value stored in memory.

Declaring and Assigning

Variables have to be declared before they can be used. From ES6 onwards, JavaScript uses the keywords const and let to declare variables. The keyword const is used when the variable will not be reassigned to another value, whereas let is used if the variable might be reassigned later in the program.

To assign a value to a constant or variable, we use the = operator.

This example shows how we would declare a variable called name and assign the string literal ‘Alexa’ to it:

const name = 'Alexa'; // This won't be assigned to another string

This example shows how we would declare the variable score and assign it a value of the number literal 0 :

let score = 0; // This value may change during the program

To see the value of a variable, simply enter it in the console and press enter.

name<< 'Alexa'

The constant name now has a value of the string literal ‘Alexa’, so it will behave in exactly the same way. Any reference to name will be as if you had entered the string literal:

typeof name;<< 'string'

This is a useful way of dealing with long strings or expressions as it saves us from typing them over and over again.

You can even declare and assign multiple variables at the same time if you separate them with commas:

let x = 3, y = 4, z = 5;

Variables that have been declared using the let keyword can be reassigned to another value at some point later in the program. This is done by simply putting them equal to the new value. For example, we would update the score variable to have a value of 5, like so:

score = 5;

In contrast, using const means you can’treassignthe variable to another value. That means that if a variable is assigned to a primitive data type, then the value can’t be changed, and will result in an error if you attempt to:

const name = 'Alexa';name = 'Siri';<< TypeError: Assignment to constant variable.

If the variable references a non-primitive data type, such as an array, function or object, then using const will not make itimmutable. This means the underlying data inside the objectcanchange (known asmutatingthe object). We can see this in the example below:

const name = { value: 'Alexa' }; // an objectname.value = 'Siri'; // change the value<< 'Siri'

Don’t worry if you don’t quite follow the notation used in this example. We’ll cover it in Chapter 5. The important thing to note is that the value property of the object referenced by the variable name was changed from ‘Alexa’ to ‘Siri’.

This highlights an important point. Even if you use const to declare a variable, non-primitive data types can still be mutated later in the program.

Using const prevents you from reassigning a variable to another object, as it will produce an error, as illustrated below:

// declare objectconst name = { value: 'Alexa' };// attempt to reassign to another objectname = { value: 'Siri' }<< TypeError: Assignment to constant variable.

It may seem like a restriction to use const , but it actually helps make your programs more predictable if the assignment to variables can’t change. For this reason, you should try to use const to declare most variables. This helps to avoid any bugs caused by unexpected changes in assignment.

What happened to var ?

In versions of JavaScript previous to ES6, variables were declared using the keyword var . The following code shows how a variable called number would be declared and assigned the value of 2 :

var number = 2;

This worked in much the same way as using let . The main difference was that variables declared using let and const have block scope, which is discussed in more detail below. They also prevent you from overwriting any built-in methods by assignment, which is generally frowned upon, whereas using var doesn’t.

So why was the new word let introduced into ES6? Why not just change the behavior of var ?

Remember that a core tenet of the JavaScript language is that it has to remain backwardly compatible. This means that the behavior of var had to remain consistent, so couldn’t just be changed in ES6. For that reason, the new keyword let was introduced.

You should be aware of var though, as you will see it used frequently in older code examples around the web to declare variables.

Scope

Using const and let to declare variables means they areblock scoped, so their value only exists inside the block they are declared in.

Scope is an important concept in programming. It refers to where a constant or variable is accessible by the program. There are two common scopes that are often referred to in programs: global scope and local scope.

Global Scope

Any variable declared outside of a block is said to haveglobal scope. This means it is accessible everywhere in the program. While this may seem to be a good idea at first, it is not considered good practice. A ninja programmer will try to keep the number of global variables to a minimum, because any variables that share the same name will clash and potentially overwrite each other’s values. It might seem unlikely that this would happen, but it is all too common in large programs when you forget which variables you have used. There are also conventions where the same variable name is used in different situations. It can also be a problem when you are writing code in teams, or if you’re using code libraries that may use the same variable names as some of your own code.

Local Scope

In ES6, blocks can be used to create alocal scope. This means that any variables defined inside a block using the let or const will only be available inside that block and not be accessible outside of that block. This is known as having local scope, as the variable is only visible in the locality of the block.

If let or const are not used, the variable will have global scope and be available outside the block. This can be demonstrated in the following example, where the variable a can have two different values depending on whether it is defined inside or outside a block:

const a = 1;{ const a = 3; a; }<< 3

Now check the value of a outside the block:

a;<< 1

In the example, a is initially defined globally outside the block and is given the value of 1 . This means it has global scope and is available inside and outside the block. But then a is defined inside the local block using let . This gives it local scope inside the block where it has a value of 3 , but it retains the value of 1 outside the block. For all intents and purposes, the two a variables are different variables.

Here’s another example where we define a global variable and then overwrite it from within the block:

let b = 2;{ b = 4; b; }<< 4

Now check the value of b outside the block:

b;<< 4

In this example, b is defined globally outside the block and given the value of 2 . Then we reassign the value of b to 4 inside the block, butwithoutusing let . This means that it still refers to the global variableoutsidethe block, so the value of b is the same both inside and outside the block and it gets overwritten globally to be a value of 4 .

In the next example, we’ll create a global variable from within a block that is then still accessible from outside of the block:

{ c = 5; c; }<< 5

Now check the value of c outside the block:

c;<< 5

In this example, c is defined inside the block, but because this is done without using let or const , it has global scope and is also available outside the block.

In the last example we’ll create a local variable, d , inside a block that is not accessible outside the block:

{ const d = 6; d; }<< 6

Now check the value of d outside the block:

d;<< ReferenceError: d is not defined

In this example, d is defined inside the block, but by using const so it has local scope and is only accessible inside the block. When we try to log the value of d outside the block, it causes an error because d is not defined globally.

Using let or const to declare variables will ensure they are block scoped, and it is good practice to always use them to declare variables. In general, if a value is unlikely to change in your code then you should declare it using const , and let should only be used for storing values that will need to be reassigned while the program is running.

Naming Constants & Variables

When naming constants and variables, you should try to give them sensible names that describe what the variable represents; hence, answer is a better variable name than x .

Constant and variable names can start with any upper or lower-case letter, an underscore, _ , or dollar character, $ . They can also contain numbers, but cannot start with them.

Here are some valid examples:

$name_answerfirstNamelast_nameaddress_line1

Variable Naming

Variables that start with an underscore generally refer to private properties and methods, so it’s best to not follow this convention for your own variable names.

The $ character is also used by the popular jQuery library, so using this in your variable names may also cause problems.

Constant and variable names are case sensitive, so ANSWER is different to Answer and answer .

When using multiple words for constant and variable names there are two conventions:

Camel casestarts with a lowercase letter and then each new word is capitalized:

firstNameAndLastName

Underscoreseparates each new word with an underscore:

first_name_and_last_name

JavaScript’s built-in functions use the camel-case notation and this is probably the best convention to follow when naming the constants and variables in your code. The most important thing is tobe consistent.

Direct Assignment and Assignment By Reference

When you assign a primitive value to a variable, any changes you make are made directly to that value:

const a = 1;let b = a; // a = 1, b = 1b = 2; // a = 1, b = 2

In the example above, a references the primitive number 1 . We then assign b to the same value as a . At this point a and b both have the same value of 1 . Then we reassign the value of 2 to b , but the a still has a value of 1 .

But if you assign a non-primitive value to a variable, then this is done byreference, so any changes that are subsequently made will affectallreferences to that object:

const c = { value: 1 };let d = c; // c.value = 1, d.value = 1d.value = 2; // c.value = 2, d.value = 2

In the example above, the change to the value property of d also results in the value property of c changing as well. This is because the variables c and d are both referencing thesameobject, so any changes to one of them will also affect the other.

Strings

A string is a collection of characters, such as letters and symbols. We can create a string literal by writing a group of characters inside quote marks like this:

'hello'

Variables that start with an underscore, generally refer to private properties and methods, so it’s best to not follow this convention for your own variable names.

The $ character is also used by the popular jQuery library, so using this in your variable names may also cause problems.

Using a Constructor Function

You can also create a string object using the following constructor function:

new String("hello")<< [String: 'hello']

This will create a new string that is the same as the string literal ‘hello’, although it will be classed as an object rather than a primitive data type. For this reason it is preferable to use the string literal notation, not to mention it requires less typing to use literals!

The same string literal can be created using single quote marks:

'hello'

If you want to use double quote marks inside a string literal, you need to use single quote marks to enclose the string. And if you want to use an apostrophe in your string, you will need to use double quote marks to enclose the string, otherwise the apostrophe will terminate the string, causing an error:

'It's me' // causes an error"It’s me" // this works

Another option is toescapethe quotation mark. You place a backslash before the apostrophe so it appears as an apostrophe inside the string instead of terminating the string:

'It\'s me'

Backslashes

The backslash is used to escape special characters in strings such as:

  • Single quote marks \'
  • Double quote marks \"
  • End of line \n
  • Carriage return \r
  • Tab \t

If you want to actually write a backslash, you need to escape it with another backslash:

"This is a backslash \\"<< "This is a backslash \"

String Properties and Methods

Primitive data types and objects have properties and methods. Properties are information about the object or value, while methods perform an action on the object or value ― either to change it or to tell us something about it.

Wrapper Objects

Technically, only objects have properties and methods. JavaScript overcomes this by creatingwrapper objectsfor primitive data types. This all happens in the background, so for all intents and purposes it appears that primitive data types also have properties and methods.

We can access the properties of a string using dot notation. This involves writing a dot followed by the property we are interested in. For example, every string has a length property that tells us how many characters are in the string:

const name = 'Alexa'; // declare and assign a variable<< 'Alexa'name.length; // retrieve the name variable's length property<< 5

As you can see, this tells us that there are five characters in the string stored in the name constant.

Good Habits

You may have noted that we’re using the const keyword to declare the variable above. We also finished each line with a semicolon. Strictly speaking, this isn’t really required for these short examples, but it’s good practice and we’ll be doing it in all the examples in the book. I would encourage you to do the same so you get yourself into a good habit. Believe me, it will be useful by the time we are writing larger, more complex applications later in the book.

An alternative notation you can use to access a primitive data type’s properties are square brackets:

name['length']; // note the property name is in quote marks<< 5

It’s usually more common to use the dot notation due to it requiring less typing, although there are some occasions, which we’ll come across later in the book, when the square bracket notation is preferable.

All properties of primitive data types are immutable, meaning they’re unable to be changed. You can try, but your efforts will be futile:

name.length;<< 5name.length = 7; // try to change the length<< 7name.length; // check to see if it's changed<< 5

A method is an action that a primitive data type or object can perform. To call a method, we use the dot operator ( . ) followed by the name of the method, followed by parentheses (this is a useful way to distinguish between a property and a method ― methods end with parentheses). For example, we can write a string in all capital letters using the toUpperCase() method:

name.toUpperCase();<< 'ALEXA'

Or the toLowerCase() method, which will write my name in all lower-case letters:

name.toLowerCase();<< 'alexa'

If you want to know which character is at a certain position, you can use the charAt() method:

name.charAt(1);<< 'l'

This tells us that the character ‘l’ is at position 1. If you were thinking that it should be ‘A’, this is because the first letter is classed as being at position 0 (you’ll find that counting usually starts at zero in programming!).

If you want to find where a certain character or substring appears in a string, we can use the indexOf() method:

name.indexOf('A');<< 0

If a character doesn’t appear in the string, -1 will be returned:

name.indexOf('z');<< -1

If we want the last occurrence of a character or substring, we can use the lastIndexOf() method:

name.lastIndexOf('a');<< 4

If all we want to know if a string contains a certain character, then ES2016 provides the useful includes() method:

name.includes('a');<< truename.includes('z');<< false

ES6 added a couple of methods to check if a string starts or ends in a particular character.

To check if a string starts with a certain character, we can use the startsWith() method. Be careful though, it’s case-sensitive:

name.startsWith('A');<< truename.startsWith('a');<< false

And we can use the similar endsWith() method to check if a string ends with a particular character:

name.endsWith('A');<< falsename.endsWith('a');<< true

The concat() method can be used to concatenate two or more strings together:

'JavaScript'.concat('Ninja');<< 'JavaScriptNinja''Hello'.concat(' ','World','!');<< 'Hello World!'

A shortcut for string concatenation is to use the + operator to add the two strings together:

'Java' + 'Script' + ' ' + 'Ninja';<< 'JavaScript Ninja'

The trim() method will remove any whitespace from the beginning and end of a string:

'    Hello World     '.trim(); // the space in the middle will be preserved<< 'Hello World''   \t\t  JavaScript Ninja! \r'.trim(); // escaped tabs and carriage returns are also removed<< 'JavaScript Ninja!'

ES6 also introduced the repeat() method that will repeat a string the stated number of times:

'Hello'.repeat(2);<< 'HelloHello'

Template Literals

Template literalsare a special types of string that were introduced in ES6. Template literals use the backtick character, ` , to deliminate the string, as shown in the example below:

`Hello!`;

This has the advantage of being able to use both types of quote mark within the string:

`She said, "It's Me!"`

They also allow interpolation of JavaScript code. This means that a JavaScript expression can be inserted inside a string and the result will be displayed, as can be seen in the examples below:

const name = `Siri`;`Hello ${ name }!`;<< 'Hello Siri!'const age = 39;`I will be ${ age + 1 } next year`;<< 'I will be 40 next year'

The JavaScript expression is placed inside the curly braces with a $ character in front of them. This is then evaluated and the result is returned in the string output.

Template literals can also contain line breaks, which are all converted into a Line Feed (\n):

`This is the start ....... and this is the end`<< 'This is the start ...\n\n\n.... and this is the end'

If you want to place a backtick inside a template literal, then it needs to be escaped in the usual way, using a backslash:

`This character, \`, is a backtick`<< 'This character, `, is a backtick'

Super-Powered Strings

Template literals can be thought of as super-powered strings as they behave in the same way as normal string literals, but with the extra power of string interpolation. For this reason, it is not uncommon to see backticks used to createallstrings in ES6 code.

Symbols

Symbols were introduced as a new primitive value in ES6. They can be used to create unique values, which helps to avoid any naming collisions.

Symbols are the only primitives that don’t have a literal form. The only way to create them is to use the Symbol() function:

const uniqueID = Symbol();

It is recommended to add a description of the symbol inside the parentheses:

const uniqueID = Symbol('this is a unique ID');

Because symbols are primitive values, the typeof operator should return a type of ‘symbol’:

typeof uniqueID;<< 'symbol'

The description acts as a string representation of the symbol and is used to log the symbol in the console, making it useful for debugging purposes:

console.log(uniqueID);<< Symbol(this is a unique ID)

You can manually access the description using the String() function:

String(uniqueID)<< 'Symbol(this is a unique ID)'

It is possible for two variables to point to thesamesymbol if the for() method is used when the symbol is created:

const A = Symbol.for('shared symbol');const B = Symbol.for('shared symbol');

The variables A and B now both point to thesame symbolin memory. In this case the description ‘shared symbol’ also acts as a shared identifier for the symbol.

The main use-case for symbols is as object property keys, which will be covered in Chapter 5. The uniqueness of symbols, mean that it’s impossible for the names of any properties to clash with each other if they are symbols.

Thisarticle on SitePointcontains more information about symbols.

Numbers

Numbers can beintegers(whole numbers, such as 3) orfloating point numbers(often referred to as just ‘decimals’ or ‘floats’, such as 3.14159). Here are a couple of examples of number literals:

typeof 42; // integer<< 'number'typeof 3.14159; // floating point decimal<< 'number'

As you can see in the examples above, JavaScript doesn’t distinguish between integers and floating point decimals ― they are both given the type of ‘number’, which is a different approach to most other programming languages. This behavior is set out in the ECMAScript specification, but ES6 provides a handy method called Number.isInteger() that can be used to check if a number is an integer:

Number.isInteger(42);<<< trueNumber.isInteger(3.142);<< false

Constructor Function for Numbers

Just like strings, numbers also have a constructor function:

new Number(3)<< [Number: 3]

This is much more verbose than simply writing the number 3 , which is known as a number literal, so it is recommended that you stick to using number literals.

Octal and Hexadecimal Numbers

If a number starts with a 0x , it is considered to be in hexadecimal (base 16) notation:

0xAF; // A represents 10, F represents 15<< 175

Hexadecimal or “hex” numbers are often used for color codes on the Web. You canread more about them on Wikipedia.

ES6 now supports octal literals: If a number starts with a zero, followed by the letter o , then it is considered to be in octal (base 8) notation:

0o47; // 4 eights and 7 units<< 39

ES6 also supports binary literals: If a number starts with a zero, followed by the letter b then it is considered to be in binary (base 2) notation:

0b1010; // 1 eight, 0 fours, 1 two and 0 units<< 10

Exponential Notation

Numbers can also be represented in exponential notation, which is shorthand for “multiply by 10 to the power of” (you may have heard this referred to as “scientific notation” or “standard form”). Here are some examples:

1e6; // means 1 multiplied by 10 to the power 6 (a million)<< 10000002E3; // 2 multiplied by 10^3 (two thousand)<< 2000

Decimal values can be created by using a negative index value:

2.5e-3; // means 2.5 multiplied by 10 to the power -3 (0.001)<< 0.0025

Number Methods

Numbers also have some built-in methods, although you need to be careful when using the dot notation with number literals that are integers because JavaScript will confuse the dot with a decimal point. Don’t worry though, there are a few ways to deal with this, which we’ll demonstrate with the toExponential() method; this returns the number as a string in exponential notation.

Use two dots:

5..toExponential();>> "5e+0"

Put a space before the dot:

5 .toExponential(); >> "5e+0"

Always write integers as a decimal:

5.0.toExponential(); >> "5e+0"

Place the integer in parentheses:

(5).toExponential(); >> "5e+0"

Assign the number to a constant:

const number = 5;>> 5number.toExponential();>> "5e+0"

Now let’s take a look at a couple of other number methods.

The toFixed() method rounds a number to a fixed number of decimal places:

const PI = 3.1415926;<< undefinedPI.toFixed(3); // only one dot is needed when using constants or variables<< "3.142"

Note that the value is returned as a string, rather than a number.

The toPrecision() method rounds a number to a fixed number of significant figures that is once again returned as a string (and often using exponential notation):

325678..toPrecision(2);<< "3.3e+5"2.459.toPrecision(2);<< "2.5"

Arithmetic Operations

All the usual arithmetic operations can be carried out in JavaScript.

Addition:

5 + 4.3;<< 9.3

Subtraction:

6 - 11;>> -5

Multiplication:

6 * 7;&code<pre

Division:

3/7;<<0.42857142857142855

Exponentiation:

2**3; // introduced in ES2017<< 8

You can also calculate the remainder of a division using the % operator:

23%6; // the same as asking 'what is the remainder when 13 is divided by 6'<< 5

This is similar to, but not quite the same as,modular arithmetic. That’s because the result always has the same sign as the first number:

-4%3; // -4 modulo 3 would be 2<< -1

Changing The Value of Variables

If a variable has been assigned a numerical value, it can be increased using the following operation:

let points = 0; // initialize points score to zero<< 0points = points + 10;<< 10

This will increase the value held in the points variable by 10 .

A shorthand for doing this is to use thecompound assignment operator+= :

points += 10;<< 20

There are equivalent compound assignment operators for all the operators in the previous section:

points -= 5; // decreases points by 5<< 15points *= 2; // doubles points<< 30points /= 3; // divides value of points by 3<< 10points %= 7; // changes the value of points to the remainder if its current value is divided by 7<< 3

Incrementing Values

If you only want to increment a value by 1 , you can use the ++ operator. This goes either directly before or after the variable:

let points = 5;points ++<< 6

So what’s the difference between putting the ++ operator before or after the variable? The main difference is the value that is returned by the operation. Both operations increase the value of the points variable by 1 , but points++ will return the original valuethenincrease it by 1, whereas ++points will increase the value by 1, then return the new value:

points++; // will return 6, then increase points to 7<< 6++points; // will increase points to 8, then return it<< 8

There is also a -- operator that works in the same way:

points--; // returns 8, but has decreased points to 7<< 8--points; // decreases points to 6, then returns that value<< 6

Infinity

 Infinity is a special error value in JavaScript that is used to represent any number that is too big for the language to deal with. The biggest number that JavaScript can handle is 1.7976931348623157e+308:

1e308; // 1 with 308 zeroes!<< 1e3082e308; // too big!<< Infinity

There is also a value -Infinity , which is used for negative numbers that go below -1.7976931348623157e+308:

-1e309;<< -Infinity

The value of Infinity can also be obtained by dividing by zero:

1/0;<< Infinity

The smallest number that JavaScript can deal with is 5e-324. Anything below this evaluates to either 5e-324 or zero:

5e-324; zero point (324 zeros) five<< 5e-3243e-325;<< 5e-3242e-325;<< 0

NaN

 NaN is an error value that is short for “Not a Number”. It is used when an operation is attempted and the result isn’t numerical, like if you try to multiply a string by a number, for example:

'hello' * 5;<< NaN

The result returned by the typeof operator is rather ironic, however:

typeof NaN; // when is a number not a number?!?<< 'number'

Checking a Value is a Number

You can check if a value is a number that can be used by using the Number.isFinite() method. This will return true if the value is a number that isn’t Infinity-Infinity or NaN :

Number.isFinite(1/0);<< falseNumber.isFinite(-Infinity);<< falseNumber.isFinite(NaN);<< falseNumber.isFinite(42);<< true

Type Coercion

Type coercion happens when the operands of an operator are of different types. In this case, JavaScript will attempt to convert one operand to an equivalent value of the other operand’s type. For example, if you try to multiply a string and a number together, JavaScript will attempt to coerce the string into a number:

'2' * 8;<< 16

This may seem useful, but the process is not always logical or consistent and can cause a lot of confusion. For example, if you try toadda string and a number together, JavaScript will convert the number to a string and then concatenate the two strings together:

'2' + 8;<< '28'

This can make it difficult to spot type errors in your code. The best approach is to try to be very explicit about the types of values you are working with. If you need to change the type, then do it manually, rather than relying on type coercion to do it for you.

JavaScript Is Weakly Typed

JavaScript is known as aweakly typedorloosely typedlanguage. This means that you don’t need to explicitly specify what data-type a variable is when you declare it. This can lead to unexpected behavior and hard to find bugs in code, particularly when type-coercion takes place in the background.

Strongly typedlanguages such as Java or Swift require the type of variables to be specified when they are declared. Trying to use the wrong data-type will cause an error.

TypeScriptis an open source superset of JavaScript that is maintained by Microsoft. It provides the option to specify the type of variables explicitly when they are declared, effectively making it a strongly typed version of JavaScript. It also adds some extra features and is designed to be make building large-scale applications easier in JavaScript. Programs are written in TypeScript and then transpiled into JavaScript.

Converting Between Strings and Numbers

We can convert numbers to strings and vice versa using a variety of methods.

Converting Strings to Numbers

The best way to change a string to a number is to use the Number method. This will convert the string form of a number into an actual number:

Number('23');<< 23

This is the preferred way to convert strings to numbers as it avoids type coercion in the background. The conversion is also explicit and makes it obvious what is being done.

If the string cannot be converted into a number, then NaN is returned:

Number('hello');<<< NaN

There are a few ‘tricks’ that can also be used to convert a string into a number that use type coercion. For example we can multiply a numerical string by 1 , which will coerce it into a number:

const answer = '5' * 1;<< 5typeof answer;<< "number"

Another trick is to simply place a + operator in front of it:

const answer = +'5';<< 5typeof answer;<< 'number'

These methods are very hacky and not recommended, but you may see them used every now and then in code examples.

Converting Numbers to Strings

The preferred way of changing a number to a string is to use the String function:

String(3);<< '3'

You can also use type coercion by ‘adding’ an empty string, although this isn’t recommended:

3 +'';<< '3'

Another option is to use the toString() method:

10..toString();<< '10'

This can also be used to change the base of the number. For example, if you want to write the number 10 in binary (base two), you could write:

10..toString(2);<< '1010'

You can go up to base 36, although after base 10, letters are used to represent the digits:

> 28101..toString(36) // a million in base 36<< 'lol'

Parsing Numbers

There is also a useful function called parseInt() that can be used to convert a string representation of a numerical value back into a number. You can specify the base of the number you are trying to convert, for example:

parseInt('1010',2); // converts from binary, back to decimal<< 10parseInt('omg',36);<< 31912parseInt('23',10);<< 23

If a string starts with a number, the parseInt function will use this number and ignore any letters that come afterwards:

const address = '221B Baker Street';parseInt(address, 10)<< 221

This is different to the Number function, which returns NaN :

Number(address);<< NaN

And if you use parseInt with a decimal, it will remove anything after the decimal point:

parseInt('2.4',10);<< 2

Be careful not to think that this is rounding the number to the nearest integer; it simply removes the part after the decimal point, as seen in this example:

parseInt('2.9',10);<< 2

There is also a similar function called parseFloat() that converts strings into floating point decimal numbers:

parseFloat('2.9',10);<< 2.9

Undefined

 Undefined is the value given to variables that have not been assigned a value. We’ve already seen it used earlier in this chapter when variables are declared without being assigned a value. It can also occur if an object’s property doesn’t exist or a function has a missing parameter. It is basically JavaScript’s way of saying “I can’t find a value for this.”

Null

 Null means ‘no value’. It can be thought of as a placeholder that JavaScript uses to say “there should be a value here, but there isn’t at the moment.”

If this reminds you a lot of undefined then this is because they are both ‘non-value’ values, meaning they are similar, but behave slightly differently. For example, if you try to do sums with them:

10 + null; // null behaves like zero<< 1010 + undefined; // undefined is not a number<< NaN

 null is coerced to be 0 , making the sum possible whereas undefined is coerced to NaN , making the sum impossible to perform.

In general, values tend to be set to undefined by JavaScript, whereas values are usually set to null manually by the programmer.

Booleans

There are only two Boolean values: true and false . They are named after George Boole, an English mathematician who worked in the field of algebraic logic. Boolean values are fundamental in the logical statements that make up a computer program. Every value in JavaScript has a Boolean value and most of them are true (these are known astruthyvalues).

To find the Boolean value of something, you can use the Boolean function like so:

Boolean('hello');<< trueBoolean(42);<< trueBoolean(0);<< false

Only 9 values are always false and these are known asfalsyvalues:

* "" // double quoted empty string literal* '' // single quoted empty string literal* `` // empty template literal* 0* -0 // considered different to 0 by JavaScript!* NaN* false* null* undefined

Truthy? Falsy?

The fact that empty strings and zero are considered falsy can be problematic at times, especially since most other programming languages don’t behave in the same way. For this reason, a ninja programmer needs to be especially careful when dealing with numbers that might be zero, or strings that are empty.

For more on truthy and falsy values, seethis article on SitePoint.

Logical Operators

A logical operator can be used with any primitive value or object. The results are based on whether the values are considered to be truthy or falsy.

! (Logical NOT)

Placing the ! operator in front of a value will convert it to a Boolean and return the opposite value. So truthy values will return false , and falsy values will return true . This is known asnegation:

!true; // negating true returns false<< false!0; // 0 is falsy, so negating it returns true<< true

You can use double negation ( !! ) to find out if a value is truthy or falsy (it is a shortcut to using the Boolean function we employed earlier because you are effectively negating the negation):

!!'';<< false!!"hello";<< true!!3;<< true!!NaN;<< false!!"false";<< true!!'0';<< true

&& (Logical AND)

Imagine a nightclub that only allows people inside if they are wearing shoes AND over 18. This is an example of a logical AND condition: anybody going into the club must satisfybothconditions before they are allowed in.

The logical AND operator works on two or more values (the operands) and only evaluates to true ifallthe operands are truthy. The value that is returned is thelasttruthy value if they are all true, or thefirstfalsy value if at least one of them is false:

'shoes' && 18; // both values are truthy<< 18'shoes' && 0; // returns 0 because it is falsy<< 0

|| (Logical OR)

Now imagine that the club relaxes its rules and allows people in if they wear shoes OR they’re over 18. This means they only have to satisfy one of the rules to be allowed in. This is an example of a logical OR condition.

The logical OR operator also works on two or more operands, but evaluates to true ifanyof the operands are true, so it only evaluates to false if both operands are falsy. The value that is returned is thefirsttruthy value if any of them are true, or thelastfalsy value if all of them are false:

'shoes' || 0;<< 'shoes'NaN || undefined;  // both NaN and undefined are falsy, so undefined will be returned<< undefined

Lazy Evaluation

Remember the rule that people going to the nightclub had to wear shoesandbe over 21? If a bouncer saw somebody wasn’t wearing shoes, there’d be no point in asking them for ID to check their age they wouldn’t be allowed in anyway.

When the rules were relaxed, people were allowed in if they were wearing shoesorif if they were over 18. If somebody arrived wearing shoes, there would be no need for a bouncer to check their age, since only one of the conditions needed to be met.

These are examples of lazy evaluation ― you only check the minimum number of criteria that needs to be met. JavaScript performs a similar task and uses lazy evaluation when processing the logical AND and OR operators. This means it stops evaluating any further operands once the result is clear.

For example, for a logical AND expression to be true , all the operands have to be true; if any of them are false , there is no point checking any subsequent operands as the result will still be false. Similarly, for a logical OR to be true , only one of the operands has to be true; hence, as soon as an operand is evaluated to true , the result is returned as true and any subsequent operands won’t be checked as the result is of no consequence.

An example of this being used is when the operands are used for assignment. You have to be aware that some assignments might not be made because JavaScript will not bother evaluating all of the operands.

This can be seen in the examples below:

let a = 0; // declare the variable a and assign the value of 0<< 0false && (a = 1); // (a = 1) is truthy, but it won't be evaluated, since the first operand is false<< falsea // the value of a is still 0<< 0false || (a = 1); // this will evaluate both operands, so a will be assigned the value of 1, which is returned<< 1

Bitwise Operators

Bitwise operators work with operands that are 32-bit integers. These are numbers written in binary (base two) that have 32 digits made up of just 0 s and 1 s. Here are some examples:

5 is written as   00000000000000000000000000000101100 is written as 0000000000000000000000000110010015 is written as  00000000000000000000000000001111

JavaScript will convert any values used with bitwise operators into a 32-bit integer then carry out the operation. It then changes it back into a base 10 integer to display the return value.

Bitwise operators tend to only be used for low-level programming tasks or applications that require a number of on-off states. They are unlikely to be used often, but are included here for completeness.

Bitwise NOT

The bitwise NOT operator ~ will convert the number to a 32-bit integer, then change all the 1 s to 0 and all the 0 s to 1 s. It then returns the new value as an integer.

For example, 2476 can be represented as:

00000000000000000000100110101100

Which will change to:

11111111111111111111011001010011

This is 4294964819, but the result actually uses negative values, as you can see in the code:

~2476;  << -2477

This means that in most cases, this operator will return an integer that adds to the original operand to make -1.

Bitwise AND

The bitwise AND operator, & , will convert both numbers into binary, and returns a number that in binary has a 1 in each position for which the corresponding bits of both operands are 1 s. Here’s an example:

12 & 10; // in binary this is 1100 & 1010, so only the first digit is 1 in both cases. This returns 1000, which is 8 in binary<< 8

Bitwise OR

There is also the bitwise OR operator, | , which will convert both numbers into binary and return a number that in binary has a 1 in each position for which the corresponding bits of either operands are 1 s. Here’s an example:

12 | 10; // in binary this is 1100 & 1010, so the first 3 digits contain a 1, returning 1110, which is 14 in binary<< 14

Bitwise XOR

Another operation is the bitwise XOR operator, ^ , which stands for “eXclusive OR”. This will convert both numbers into binary and return a number that in binary has a 1 in each position for which the corresponding bits of either operands are 1s, but not both 1 s. Here’s an example:

12 ^ 10; // in binary this is 1100 & 1010, so only the second and third digits are exclusively 1s, so 0110 is returned, which is 6 in binary<< 6

Don’t use ^ to notate exponents

The ^ character is often used as an informal notation for exponents, so be careful not to use this mistakenly when programming in JavaScript. For example 2^3 willnotreturn 8 . There is a specific Math method for doing this that is covered in Chapter 5, and ES2017 introduced the exponent operator ** , that allows you to write it as 2**3 .

When using non-integer values, this evaluates to 1 ifeitheroperands are truthy and evaluates to 0 if both operands are truthy or both are falsy:

1 ^ 0; // The first operand is truthy<< 1true ^ true; // if both operands are true then the result is false<< 0

Bitwise Shift Operators

The bitwise shift operators, << and >>, will move the binary representation a given number of places to the right or left, which effectively multiplies or divides the number by powers of two:

3 << 1; // multiply by 2<< 616 >> 1; // divide by 2<< 85 << 3; multiply by 2 cubed (8)<< 40

More information about bitwise operators can be found on theMozilla Developer Network

Comparison

We often need to compare values when programming. JavaScript has several ways to compare two values.

Equality

Remember earlier, when we assigned a value to a variable? We used the = operator to do this, which would be the logical choice for testing if two values are equal.

Unfortunately, we can’t use it because it’s used for assigning values to variables. For example, say we had a variable called answer and we wanted to check if it was equal to 5 , we might try doing this:

const answer = 5;<< 5

What we’ve actually done isassignthe value of 5 to the variable answer , effectively overwriting the previous value!

The correct way to check for equality is to use either a double equals operator, == , known as “soft equality” or the triple equals operator, === , known as “hard equality”.

Soft Equality

We can check if answer is in fact equal to 5 using the soft, or lenient, equality operator == , like so:

answer == 5;<< true

This seems to work fine, but unfortunately there are some slight problems when using soft equality:

answer == "5";<< true

As you can see, JavaScript is returning true when we are checking if the variable answer is equal to thestring“5”, when in fact answer is equal to thenumber5. This is an important difference, but when a soft inequality is used, JavaScript doesn’t take into account the data type and will attempt to coerce the two values to the same type when doing the comparison. This can lead to some very strange results:

" " == 0;<< true" " == "0";<< falsefalse == "0";<< true"1" == true;<< true"2" == true;<< false"true" == true;<< falsenull == undefined;<< true

As you can see, some values that are not actually equal to each other have a tendency to be reported as being equal when using the soft equality operator.

Hard Equality

The hard, or strict, equality operator, === , tests for equality but only returns true if and only if they are of the same data type:

answer === 5;<< trueanswer === '5';<< falsenull === undefined;<< false

As you can see, hard equality reports that the variable answer is the number 5, but not the string “5”. It also correctly reports that null and undefined are two different values.

Hard Equality’s One Quirk

The only strange result produced by hard equality is this:

NaN === NaN;<< false

NaN is the only value in JavaScript that is not equal to itself! To deal with this, there is a special Number method called Number.isNaN() to test it:

Number.isNaN(NaN);<< trueNumber.isNaN(5);<< false

The Number.isNaN() method is new to ES6 and replaces the global isNaN() method. This old method has the unfortunate property of reporting strings as NaN as well as NaN itself, as can be seen in the example below:

isNaN('hello');<< true

This is because of our old nemesis, type coercion! The function first of all tries to convert the string to a number, and strings without numerals are converted to NaN:

Number('hello');<< NaN

Because of this, the new Number.isNaN() method should always be used to check if a value is NaN .

A JavaScript ninja should always use hard equality when testing if two values are equal. This will avoid the problems caused by JavaScript’s type coercion.

If you want to check whether a number represented by a string is equal to a number, you should convert it to a number yourself explicitly rather than relying on type coercion happening in the background:

Number('5') === 5<< true

This can come in handy when you’re checking values entered in a form as these are usually always submitted as strings.

Inequality

We can check if two values arenotequal using the inequality operator. There is a soft inequality operator, != and a hard inequality operator, !== . These work in a similar way to the soft and hard equality operators:

16 != '16'; // type coercion makes these equal<< false16 !== '16';<< true

As with equality, a ninja programmer should use the hard inequality operator as this will give more reliable results unaffected by type coercion.

Greater Than and Less Than

We can check if a value is greater than another using the > operator:

8 > 4;<< true

You can also use the “less than” < operator in a similar way:

8 < 4;<< false

If you want to check if a value is greater thanor equalto another value, you can use the >= operator, :

8 >= 4;<< true8 >= 8;<< true

But be careful; the equality test works in the same way as the soft equality operator:

8 >= '8';<< true

As you can see, type coercion means that strings can be confused with numbers. Unfortunately, there are no “hard” greater-than or equal-to operators, so an alternative way to avoid type coercion is to use a combination of the greater-than operator, logical OR, and a hard equality:

8 > 8 || 8 === 8;<< true8 > '8' || 8 === '8';<< false

There is also a similar “less-than or equal-to” operator:

-1 <= 1;<< true-1 <= -1;<< true

These operators can also be used with strings, which will be alphabetically ordered to check if one string is “less than” the other:

'apples' < 'bananas';>> true

Be careful, though, as the results are case-sensitive, and upper-case letters are considered to be “less than” lower-case letters:

'apples' < 'Bananas';>> false

Quiz Ninja Project

Now that we have come to the end of the chapter, it’s time to put what we’ve learned into practice in our Quiz Ninja project.

Since we’ve been learning all about JavaScript in this chapter, we’re going to add some code in the main.js file. Open that file and add the following lines:

const question = "What is Superman's real name?"const answer = prompt(question);alert(`You answered ${answer}`);

Now let’s go through this code line by line to see what is happening:

const question = 'What is Superman's real name?';

This declares a variable called question and assigns the string ‘What is Superman’s real name?’ to it.

Next, we need to ask the question stored in the question variable, using a prompt dialog:

const answer = prompt(question);

A prompt dialog allows the player to type in a response, which is then stored in the variable it is assigned to, which is answer in this case.

Finally, we use an alert dialog to display the player’s answer using string interpolation to insert the value of answer into the template literal that is displayed in an alert box:

alert(`You answered ${answer}`);

This shows the player the answer they provided. In the next chapter we’ll look at how to check if it’s correct.

Have a go at playing the quiz by opening the index.html file in your browser. It should look a little like the screenshot in below.

Let’s play Quiz Ninja!

You can also see a live example onCodePen.

This is a good example of using the prompt and alert dialogs, along with variables to store the responses in to create some interactivity with the user.

Chapter Summary

  • Comments are ignored by the program, but make your program easier to read and understand
  • Data types are the basic building blocks of all JavaScript programs.
  • There are six primitive data types: strings, symbols, numbers, Booleans, undefined and null.
  • Non-primitive data types, such as arrays, functions and objects, all have a type of ‘object’.
  • Variables point to values stored in memory and are declared using the const or let keywords.
  • Values are assigned to variables using the = operator.
  • Strings and numbers have various properties and methods that provide information about them.
  • Symbols are unique, immutable values.
  • Boolean values are either true or false .
  • There are only seven values that are false in JavaScript and these are known as ‘falsy’ values.
  • Data types can be converted into other data types.
  • Type coercion is when JavaScript tries to convert a value into another data type in order to perform an operation.
  • Logical operators can be used to check if compound statements are true or false.
  • Values can be compared to see if they are equal, greater than or less than other values.

In the next chapter, we’ll be looking at data structures, logic, and loops.

Pages: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16