308H.1 - Introduction to JavaScript

Learning Objectives

By the end of this lesson, learners should be able to:

  • Use JavaScript data types.
  • Write JavaScript comments.
  • Differentiate between var, let, and const.
  • Use JavaScript operators.

JavaScript as a Programming Language

JavaScript is a high-level and weakly typed scripting programming language. "High-level" indicates that it does not deal directly with CPU processes, memory allocations, or other low-level processes. "Weakly typed" means that JavaScript variables do not need to be declared as a specific data type (which we will cover later in this lesson) like in some other programming languages.

Modern JavaScript is a “safe” programming language, because it does not provide low-level access to memory or CPU; it was initially created for browsers, which do not require that level of access.

JavaScript Facts:

  • JavaScript was initially created to make web pages more dynamic.
  • JavaScript programs are called scripts. They can be written right in the HTML, and execute automatically as the page loads or in response to events. Scripts are provided and executed as plain text, and they do not need a special preparation or a compilation to run, as JavaScript is an interpreted language. The JavaScript interpreter (embedded in the browser) is responsible for translating JavaScript code for the browser.
  • It is important to note that JavaScript has almost nothing to do with the programming language named Java. The similar name was inspired by marketing considerations when JavaScript was introduced.

JavaScript Capabilities

JavaScript’s capabilities greatly depend on the environment that runs JavaScript. For instance, Node.JS supports functions that allow JavaScript to read and write arbitrary files, perform network requests, etc.

In-browser JavaScript can do everything related to web page manipulation and interaction with the user and the web server. For example, in-browser JavaScript is able to:

  • Add new HTML to the page, change the existing content, and modify styles.
  • React to user actions, and run code on mouse clicks, pointer movements, and key presses.
  • Send requests over the network to remote servers, and download and upload files.
  • Get and set cookies, ask questions to the user, and show messages.
  • Remember data on the client-side (via “local storage”).

JavaScript Restrictions

JavaScript’s abilities in the browser are limited for the sake of the user’s safety. The aim is to prevent a malicious web page from accessing private information or harming the user’s data.

Examples of such restrictions include:

  • JavaScript on a webpage may not read/write or copy arbitrary files on the hard disk, or execute programs. It has no direct access to operating system functions.
  • Modern browsers allow JavaScript to work with files, but the access is limited and only provided if the user performs certain actions, such as “dropping” a file into a browser window or selecting it via an <input> tag.
  • There are ways to interact with the camera, microphone, and other devices, but they require a user’s explicit permission. A JavaScript-enabled page may not sneakily enable a web-camera, observe the surroundings, and send the information to some mysterious entity, for instance.

Different tabs and browser windows are generally unaware of each other. However, there are times when they can be aware of each other (e.g., when one window uses JavaScript opens the other one). In such cases, JavaScript from one page may not access the other if they come from different sites (e.g., different domain, protocol, or port). This is called the “Same Origin Policy.” To work around that, both pages must contain JavaScript code that handles data exchange between them:

  • The limitation is again for user safety. A page from http://anysite.com, which a user has opened must not be able to access another browser tab with the URL http://gmail.com and steal information from there.
  • JavaScript can easily communicate over the internet to the server where the current page came from, but its ability to receive data from other sites or domains is constrained. Though it is possible, it requires explicit agreement (expressed in HTTP headers) from the remote side.

Basic JavaScript Grammar

JavaScript borrows most of its syntax from Java, C, and C++, but it has also been influenced by Awk, Perl, and Python. If you have worked with any of these languages in the past, JavaScript will look very familiar.

JavaScript is case-sensitive and uses the Unicode character set. This means that even special characters within the Unicode set can be used in JavaScript source code, such as for variable names (more on this later).

In JavaScript, instructions are called statements, and each statement is separated with a semicolon (;). You will see semicolons omitted from some statements in JavaScript; this is because they are not strictly required if a statement is written on its own line. However, it is considered best practice to always include a semicolon after a statement, even when it is not strictly needed. This practice greatly reduces the chances of bugs in your code.

JavaScript files are read from top to bottom, left to right. The JavaScript engine, which runs the JavaScript code, converts scripts into a sequence of input elements, such as identifiers, keywords, literals, punctuators, white space, and comments.


Keywords and Reserved Words

In programming, there are certain words that carry special meaning to the program. Words like "true" and "if" control the behavior of the code, and tell JavaScript what to do. These words are called reserved words, and they cannot be used out of the proper context.

As an example, you cannot name one of your variables "default," because JavaScript expects "default" to have specific purpose and meaning. As you continue exploring JavaScript, you will run into most if not all of these reserved words in their appropriate contexts.

For now, here's a list of all of the reserved words so that you can avoid using them improperly. Don't worry about memorizing this list; if you use one of these words improperly, JavaScript will let you know.


Comments in JavaScript

Comments help document code and increase organization and readability, which is especially helpful when multiple programmers are working on the same content.

Comments in JavaScript can be written with two forward slashes //, which are referred to as line comments, as they end at the physical line end.

// This is a single line comment.

Comments can also start with /** and end with */ and can span as many lines as needed, which are referred to as block comments.

/*
 * This is a block comment.
 * It spans multiple lines.
 */

Comments are ignored by the interpreter in JavaScript, which means that they will not affect the code in any way. It is important to use comments liberally, as well-documented code is easier to scale and maintain.


Console.log and <script> Tags

The console object provides access to the browser's debugging console, and can be accessed from any global object.

log() is a method of the console object, which allows for any value type to be displayed in the browser’s console or in the server-side console. This is an important method for testing and debugging purposes, which we will make use of later.

The <script> tag allows you to embed JavaScript into an HTML page. It can have attributes such as type and src.

  • The type attribute allows you to specify the type of text you will be writing in between the opening and closing tag.
  • The src attribute allows you to link a JavaScript file external to your HTML file.

Internal script:

<script type="text/javascript">
	// do something
</script>

External script:

<script src="folder/MyJavaScriptFile.js"></script>

Data Types in JavaScript

JavaScript is a loosely typed (high-level, weakly typed, or dynamic type) language, which means that we do not need to specify data types of variables because JavaScript automatically determines the variables' data type.

Some of the available data types in JavaScript include:

  • Number – JavaScript has two different types of numbers.
  • Integers - Whole numbers such as 1, 100, 5, 100000.
  • Float - Numbers with decimal values such as 1.5, 34.33, 5.0.
  • String – A sequence of characters, including spaces, enclosed in double quotes, single quotes, or backticks.

    • “Hello to String.”
    • ‘Bye to double quotes.’
    • `Welcome to backticks.`
  • Boolean – Logical type values. Boolean can only hold two different values: true or false:
  • Null – Does not belong to any type described above. Its purpose is to indicate that there is no value. Null is an empty or non-existent value, and must be assigned.
  • Undefined – Indicates that a variable has not been assigned a value or null. Variables are often declared without a value. The value could be something that has yet to be calculated or something that will be provided later, like user input.
  • Objects – Used to store collections of data of any of the types mentioned above, or more complex entities.

Variable Declarations

A variable is a symbolic name for a memory location. The variable's name can be used to access the data the variable contains. They are called variables because the data can change.

In order to declare a variable, you can use three keywords - var, let, and const:

var myVariable = “Some value”;
let mySecond = true;
const PI = 3.141592653589793;

These declarations operate in similar ways, with a few exceptions, which will be discussed later. The semicolon at the end of the line tells JavaScript that this is the end of the statement. It is important to always include a semicolon to keep in line with best practices.

General rules for variables include:

  • Name your variables something meaningful and descriptive.
  • Start your variable names with letters or underscores, never with numbers or special characters.
  • Variables can contain numbers in the middle or at the end, but not the beginning.
  • Variables with multiple words in their name should be written in camelCase or snake_case.

The var Statement

The var statement declares a variable in JavaScript that abides by the following rules:

  • It is function-scoped or globally scoped (we will discuss scope in detail later when talking about functions).
  • It is not subject to the temporal dead zone.
  • It creates a global property on the window with the same name.
  • It is reassignable.
  • It is re-declarable.
  • It is subject to hoisting (more on this later).

You should not use var to declare variables. The use of var predates the latest JavaScript revisions, which added let and const. You should make use of let and const in all cases when coding. Future content will explain the benefits of doing so in detail.


The let Statement

The let statement declares a variable in JavaScript that abides by the following rules:

  • It is block scoped.
  • It is reassignable.
  • It is not re-declarable within its scope.
  • It is subject to hoisting.

As an example, consider the following code:

let x = 10;
// Here x is 10

{
  let x = 2;
  // Within this block, x is now 2
}

// Outside of the block, x is still 10

The const Statement

The const statement declares a variable in JavaScript that abides by the following rules:

  • It is block scoped.
  • It is not re-assignable.
  • It is not re-declarable within its scope.
  • It is subject to hoisting.

As an example, consider the following code:

const PI = 3.141592653589793;
PI = 3.14; // This will give an error.

Benefits of let and const

Since let and const are block-scoped, they allow for cleaner code with fewer errors, especially when working with large files or complex logic. As an example, consider the following code:

var counter = 1;
// Do something with this counter.

// Then, some many lines later...
function processData() {
   var counter = 1;
   // Do something with this other counter.
}

// Which counter are we referencing here?
counter++;

If our counters were declared using let, there would be no confusion, and you would not need to spend time looking through your code for the extra counter declaration that was causing errors. This allows you to reuse common variable names throughout the code.


Literals

Any value that is not a variable is a literal. They are fixed values that you literally provide to your script.

For example, this script logs three different kinds of literals: Boolean, String, and Numeric.

console.log(true);
console.log("Hello World!");
console.log(42);

As you have seen, you can assign literals to variables in order to store them as references in memory. While literals are, by themselves, a simple concept, the vocabulary is important to understand because you will hear the term "literal" used often.


The typeof Keyword

If you have a need for checking the data type of a variable (or literal), JavaScript provides the typeof keyword to do so easily.

let myVar = "Hello World!"

console.log(typeof 42);
console.log(typeof myVar);

Arithmetic Operators

Most arithmetic operations in coding can be done using the traditional operators of mathematics. Programming logic adds a few additional operators for efficient coding.

The simple arithmetic operators include:

  • The + operator, which returns the addition of two values.

    • e.g. 3 + 4 returns 7
  • The - operator, which returns the difference between two values.

    • e.g. 3 - 2 returns 1
  • The * operator, which returns the product of two values.

    • e.g. 6 * 4 returns 24
  • The / operator, which returns the division of two values.

    • e.g. 16 / 8 returns 3
  • The % operator, which returns the remainder of two values.

    • e.g. 14 % 3 returns 2

The basic arithmetic operators also have some useful shortcuts to increase coding efficiency. For example, if we were to write the following block of code to increment the value of newNumber:

let newNumber = 9;
newNumber = newNumber + 1;

We could instead use the += operator to increment newNumber, as follows:

let newNumber = 9;
newNumber += 1;

This syntax achieves the same result. You can choose any value to increment by when using this form. The same syntax applies for the other basic arithmetic operators:

let newNumber = 9;
newNumber -= 3; // newNumber is now equal to 6
newNumber /= 3; // newNumber is now equal to 2
newNumber *= 3; // newNumber is now equal to 6
newNumber %= 3; // newNumber is now equal to 0

The previous += and -= shortcuts can be further simplified for single-value increments and decrements by using ++ and , as follows.

The ++ operator increments number values by one, such as:

let newNumber = 9;
newNumber++; // newNumber is now equal to 10

The -- operator decrements number values by one, such as:

let newNumber = 9;
newNumber--; // newNumber is now equal to 8

However, if we implement the following code, currentNumber gets set to 9.

let newNumber = 9;
let currentNumber = newNumber++;

The ++ and -- operators can be placed before or after the variable they are affecting, which produces slightly different results.

When you write let currentNumber = newNumber++;, the newNumber variable will first return its current number, which is 9, and then increment its value. The result of this is that currentNumber is 9 and newNumber is 10.

let newNumber = 9;
let currentNumber = newNumber++;
// newNumber is now equal to 10, but currentNumber is equal to 9

However, when you write let currentNumber = ++newNumber;, the newNumber will increment first, and then return its value. The result of this is that currentNumber and newNumber are both 10.

let newNumber = 9;
let currentNumber = ++newNumber;
// newNumber and currentNumber are now equal to 10

The same syntax applies for the -- operator. Note that //, **, and %% are not operators in JavaScript.


Comparison Operators

Comparison operators are used to determine the relationship between certain values, and will return either true or false, depending on the result of their comparison.

  • The > operator will check if a value is strictly greater than another value.

    • e.g. 3 > 4 returns false
  • The < operator will check if a value is strictly less than another value.

    • e.g. 5 < 10 returns true
  • The >= operator will check if a value is greater than or equal to another value.

    • e.g. 78 >= 90 returns false
  • The <= operator will check if a value is less than or equal to another value.

    • e.g. 56 <= 44 returns false
  • The == operator will check if a value is only equal to another value.

    • e.g. 10 == 10 returns true
  • The != operator will check if a value is not equal to another value.

    • e.g. 10 != 30 returns true

The == operator has some unexpected behaviors. Notice that the following expressions all evaluate to true, even though 3 is an integer and “3” is a string.

let isEqual = 3 == 3; // isEqual is true
let isEqual = 3 ==3; // isEqual is true
let isEqual =3==3; // isEqual is true

So, how can a string be equal to a number?

JavaScript has two types of equal comparison:

  • == compares two values, but if they are of different data types it attempts to convert them to the same data type.

    • e.g. 3 == 3 is true, “3” == 3 is true, and 0 == false is also true.
  • === (triple equals) compares two values but does not attempt type conversion. This means that not only must the values be equal, but also their data types must also be equal.

    • e.g. 3 === 3 is true, but “3” === 3 is false.

Logical Operators

Logical operators only work with three types of values: true, false, and null. They are typically used to evaluate the results of comparison operators, which return these values. Combining logical operators allows you to evaluate more complex conditions.

The && (logical AND) operator compares two or more conditions’ results and returns true when all conditions are true.

let thisLogic = 3 > 2 && 6 == 6; // thisLogic is true
let thisLogic = 3 > 2 && 6 == 7; // thisLogic is false

The || (logical OR) operator compares two or more conditions’ results and returns true when at least one is true.

let thisLogic = 3 > 2 || 6 == 6; // thisLogic is true
let thisLogic = 3 > 2 || 6 == 7; // thisLogic is true

The ! (logical NOT) operator negates a given result.

let thisLogic = !(3 > 2 && 6 == 6); // thisLogic is false
let thisLogic = !(3 > 2 || 6 == 7); // thisLogic is false

String Concatenation

Concatenation is when two or more things are joined together. In JavaScript, the plus sign (+) operator is the only arithmetic operator that can be applied to a string. When either operand in an expression is a string, the plus sign will implement string concatenation.

Some examples of string concatenation include:

console.log(“Hello” + “ World”); // outputs: Hello World
console.log(“This is” + “ a String”); // outputs: This is a String
console.log(“The number is ” + 5); // outputs: The number is 5
console.log(“Hello” - “ World”); // Invalid, cannot use -

String Access

Working with strings is one of the most common tasks in programming, and concatenation is just the beginning.

To read an individual character within a string, you can use square bracket notation, as follows:

const name = "Inigo Montoya";

console.log(name[2]); // i
console.log("Hello World"[4]); // o

The number contained within square brackets is the index of the character you are accessing, its position within the string.

There is something strange going on, though. Shouldn't name[2] be "n" and "Hello World"[4] be "l"?

Not quite! When counting with indexes, we start at 0! Since when is 0 the first item in anything? Since computer science came along!

Internally, programs prefer to think in terms of "offsets" in memory. Thus, we access the first item using an offset of zero - things are "zero-based" in JavaScript.

While we can read from individual characters in this way, we cannot change them.

const name = "Inigo Montoya";

name[2] = "X";

console.log(name[2]); // i

In order to manipulate strings like this, we would need to use string methods. Methods are like pre-packaged bits of code that allow us to easily accomplish common or repetitive tasks. Methods are beyond the scope of this first lesson, but we will talk about them in detail during the lessons to come.


String Comparison

As we saw with the comparison operators above, we can determine whether numbers are less than, greater than, or equal to one another. Can we do the same with strings?

const a = "a";
const b = "b";

console.log(a < b); // true

It looks like we can! How exactly does this work?

JavaScript compares the strings alphabetically, such that letters that show up sooner in the alphabet are "lesser" in value than those that show up later.

You can also use this to compare whether strings are equal to one another.

console.log("Hey" === "Hey"); // true
console.log("Hey" == "hey"); // false

The example above demonstrates some important behavior: all string comparison operations are case-sensitive, even ==.


Long Literal Strings

Your code may include strings that are very long. Best practice is to split these long strings into more manageable chunks so that they do not continue endlessly within your code editor. While most code editors will wrap long lines automatically, you may also want to specifically break the string into specific lines within the source code.

So how do we do this without affecting the actual contents of the string?

First, we can use the + operator to concatenate multiple strings together across lines:

const frost =
	"Nature’s first green is gold, " +
	"Her hardest hue to hold. " +
	"Her early leaf’s a flower; " +
	"But only so an hour. " +
	"Then leaf subsides to leaf. " +
	"So Eden sank to grief, " +
	"So dawn goes down to day. " +
	"Nothing gold can stay. ";

console.log(frost);

As an alternative that is slightly cleaner, we can use the backslash character (\) at the end of each line to indicate that the string continues onto the following line. There cannot be any characters other then a line break after the backslash, or it will not work. This includes whitespace characters like space and tab, which makes this method quite particular.

const frost =
	"Nature’s first green is gold, \
Her hardest hue to hold. \
Her early leaf’s a flower; \
But only so an hour. \
Then leaf subsides to leaf. \
So Eden sank to grief, \
So dawn goes down to day. \
Nothing gold can stay.";

console.log(frost);

Both of these methods result in identical strings:

Nature’s first green is gold, Her hardest hue to hold. Her early leaf’s a flower; But only so an hour. Then leaf subsides to leaf. So Eden sank to grief, So dawn goes down to day. Nothing gold can stay.

The backslash is referred to as an escape character, and can be further combined with other specific characters to create escape sequences that provide special behavior within strings.


Escape Sequences

Here is a list of escape sequences that can be used to encode special characters:

Escape sequence Unicode code point
\0 null character (U+0000 NULL)
\' single quote (U+0027 APOSTROPHE)
\" double quote (U+0022 QUOTATION MARK)
\\ backslash (U+005C REVERSE SOLIDUS)
\n newline (U+000A LINE FEED; LF)
\r carriage return (U+000D CARRIAGE RETURN; CR)
\v vertical tab (U+000B LINE TABULATION)
\t tab (U+0009 CHARACTER TABULATION)
\b backspace (U+0008 BACKSPACE)
\f form feed (U+000C FORM FEED)
\uXXXX …where XXXX is exactly 4 hex digits in the range 0000``–FFFF; e.g., \u000A is the same as \n (LINE FEED); \u0021 is !. | Unicode code point between U+0000 and U+FFFF (the Unicode Basic Multilingual Plane)
\u{X}\u{XXXXXX} …where X``…XXXXXX is 1–6 hex digits in the range 010FFFF; e.g., \u{A} is the same as \n (LINE FEED); \u{21} is !. | Unicode code point between U+0000 and U+10FFFF (the entirety of Unicode)
\xXX …where XX is exactly 2 hex digits in the range 00FF; e.g., \x0A is the same as \n (LINE FEED); \x21 is !. Unicode code point between U+0000 and U+00FF (the Basic Latin and Latin-1 Supplement blocks; equivalent to ISO-8859-1)

Unicode characters are many, and including them all in this lesson would be folly. If you would like to learn more about Unicode, UTF-8, and UTF-16, start with a visit to the WikiPedia article on Unicode.

Since strings can be definied with either single or double quotes, you will traditionally see the string created with whichever type of quotes it does not need to use, in order to prevent the need for escaping quotes. For example:

console.log('They said, "this string does not need an escape!"');
// They said, "this string does not need an escape!"

By using single quotes to create the string, we allow the use of double quotes within (and vice versa). If we needed to use both types of quotes within the string, however, we would need to use the escape sequences as necessary:

console.log('They said, "this string doesn\'t need an escape," but that isn\'t true.');
// They said, "this string doesn't need an escape," but that isn't true.

Using these escape sequences, we could format the Robert Frost poem above using the newline sequence \n:

const frost =
	"Nature’s first green is gold, \n\
Her hardest hue to hold. \n\
Her early leaf’s a flower; \n\
But only so an hour. \n\
Then leaf subsides to leaf. \n\
So Eden sank to grief, \n\
So dawn goes down to day. \n\
Nothing gold can stay.";

console.log(frost);

Now, the poem prints line by line as it should, rather than as one long line of text.


Template Literals

Template literals are a special type of string delimited with backticks (`). These allow for multi-line strings, string interpolation with embedded expressions, and special constructs called tagged templates.

Let's explore multi-line strings using template literals:

const frost =
	`Nature’s first green is gold,
Her hardest hue to hold.
Her early leaf’s a flower;
But only so an hour.
Then leaf subsides to leaf.
So Eden sank to grief,
So dawn goes down to day.
Nothing gold can stay.`;

console.log(frost);

Just like that, it works! Our poem prints across multiple lines without any escaped newlines, thanks to the power of template literals.

Template literals include every character within the source code, including newline characters and other whitespace.

The most used feature of template literals, however, is string interpolation. Consider the following:

const a = 5;
const b = 10;

console.log("'a' is assigned a value of \"" + a + ",\" and 'b' is assigned a value of \"" + b + ".\"\n" +
"Therefore, 'a' plus 'b' is equal to " + (a + b) + ".");
// 'a' is assigned a value of "5," and 'b' is assigned a value of "10."
// Therefore, 'a' plus 'b' is equal to 15.

That's a lot of work for a relatively simple statement. Template literals provide a placeholder for JavaScript expressions to be embedded within strings through the use of the syntax ${expression}. Any valid JavaScript expression can be included within this placeholder.

Let's examine how we would accomplish the above using template literals:

const a = 5;
const b = 10;

console.log(`'a' is assigned a value of "${a}," and 'b' is assigned a value of "${b}."
Therefore, 'a' plus 'b' is equal to ${a + b}.`);
// 'a' is assigned a value of "5," and 'b' is assigned a value of "10."
// Therefore, 'a' plus 'b' is equal to 15.

Much cleaner.

Do note, however, that this means if you want to use dollar signs as part of the actual string within a template literal, they need to be escaped (\$).


Tagged Templates

Tagged templates are far beyond the scope of this lesson, but we recommend you revist them toward the end of this course. In essence, tagged templates allow you to control exactly how a template literal processes the strings and expressions within it.


Copyright © Per Scholas 2024