CTEC2712 Web application development

Introducing JavaScript

A look at the core language

Dr Graeme Stuart

Contents

  1. JavaScript is not Java
  2. ECMAScript
  3. The JavaScript console
  4. Three ways to declare variables
  5. Data types
  6. Boolean data
  7. Numbers
  8. Strings
  9. Conditionals
  10. Switch statements
  11. Basic loops
  12. Functions
  13. Arrays
  14. More array methods
  15. Looping over iterables
  16. Object literals
  17. Maps
  18. web APIs
  19. Deno

JavaScript is not Java

Brendan Eich

Java is to JavaScript as car is to carpet
- Chris Heilmann

  • Invented by Brendan Eich in 1995 for the Netscape 2 browser.
  • Originally called Mocha, then LiveScript.
  • It was renamed to Javascript to sound a bit like Java, as a marketing ploy.
  • Internet Explorer shipped with a reverse-engineered equivalent JScript in 1996
  • JScript and Javascript were incompatible, obviously.
1

ECMAScript

Brendan in 1995

  • European Computer Manufacturers Association (ECMA)
  • Netscape submitted JavaScript to ECMA International in November 1996.
  • ECMAScript specification released June 1997
  • ECMAScript 2015 (also known as ES6) was a huge update.
  • Since then, new major versions have been published every June.

logo

“ECMAScript was always an unwanted trade name that sounds like a skin disease.” - Brendan Eich

2

The JavaScript console

There are several methods of the console API that we can use.

It can be accessed via a script to log messages. Typically these messages are for the developer. We can set the visual level of our messages.

1
2
3
4
5
console.log("hello world!");
console.debug("Is this working?");
console.info('Some information')
console.warn('be aware...')
console.error("Something has failed");

We can optionally log an error with console.assert.

1
2
3
4
// Assert that an expression is true in your code.

console.assert(x > 0, "No more x!!");
// This will log an error if the first argument if false

We can display data with console.table.

1
console.table(document.location);

We can time execution with console.time and console.timeEnd.

1
2
3
console.time('mycode');
// Do some things
console.timeEnd('mycode');

The console in the browser can be used directly as a REPL interface.

3

Three ways to declare variables

TL;DR: use const by default. If you need reassignment, use let.

const

1
2
3
4
5
6
7
{
    const myConst = 1;
    myConst = 2; 
    // Uncaught TypeError: Assignment to constant variable.
}
console.log(myConst); 
// Uncaught ReferenceError: myConst is not defined
  • block-scoped
  • not reassignable

let

1
2
3
4
5
6
{
    let myVariable = 1; 
    myVariable = 2; // No problem
}
console.log(myVariable); 
// Uncaught ReferenceError: myVariable is not defined
  • block-scoped
  • reassignable

var

1
2
3
4
5
{
    var myVariable = 1; 
    myVariable = 2; // No problem
}
console.log(myVariable); // No problem
  • globally-scoped (EVIL!)
  • reassignable

Errors are good, declaring variables in the right way is good practice.

4

Data types

Data types in Javascript are pretty simple. The basic data types are Boolean, Number and String.

1
2
3
const a = true;     // Boolean
const b = 2.6;      // Number
const c = 'hello';  // String

There is also a Bigint data type for when values greater than 253 are reasonably expected.

1
const d = 1n;       // Bigint

As a dynamically typed language, JavaScript attaches type information to the data, not the variable.

Reassigning values to variables creates new objects in memory and old values are garbage collected.

1
2
3
4
5
6
7
8
let foo = 42;               // foo is now a number
foo = 'bar';                // foo is now a string
foo = true;                 // foo is now a boolean
foo = ['hello', 'world'];   // foo is now an Array
foo = {'hello': 'world'};   // foo is now an Object
foo = (a, b) => a + b;      // foo is now a function
foo = undefined;            // foo is now undefined
foo = null;                 // foo is now null
5

Boolean data

Relational, equality and logical operators return boolean values.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
let [a, b] = [1, "1"];

a < b;   // false
a > b;   // false
a == b;  // true
a != b;  // false
a === b; // false
a !== b; // true
!a       // false
!b       // false

Create Boolean values with literals, the Boolean function or double NOT operator.

1
2
3
4
const isGood = true;
const isGood = false;
const isGood = Boolean(expression);
const isGood2 = !!expression;

Boolean values are fundamental to if and while statements and e.g. the Array.filter() function,

6

Numbers

All numbers are floating point. Maths is pretty easy and obvious.

1
2
3
4
1 + 2 + 3;   // 6
1 * 2 * 3;   // 6
1 / 2 / 3;   // 0.166666666666
1 - (2 - 3); // 2

The Math namespace object allows you to do more complicated stuff.

1
2
3
4
5
6
7
Math.PI;            // 3.141592653589793
Math.round(4.7);    // 5
Math.round(4.4);    // 4
Math.sqrt(81);      // 9
Math.abs(-100);     // 100
Math.ceil(1.001);   // 2
Math.floor(1.999);  // 1

See also: Math.min, Math.max, Math.pow, Math.trunc, Math.sin, Math.cos, Math.sign, Math.random and many more…

7

Strings

String literals are specified by single or double quotes.

Basic string manipulation can be achieved with concatenation, though it is annoying and difficult to read.

1
2
const code = "CTEC2712";
const name = "Web Application Development";

String interpolation with template literals uses backticks and expressions can be included with a dollar sign and curly braces.

1
const concatenation = "Welcome to " + code + ": " + name;

String interpolation is intuitive and elegant as well as faster and better, so use it..

1
const interpolation = `Welcome to ${code}: ${name}`;

Strings have loads of useful methods like includes, replace, trim and split.

8

Conditionals

Use if...else to execute a block conditionally.

Whatever you pass into the if clause will be converted to boolean. If its not truthy, then the block will be skipped.

The else clause is optional. Further else if() clauses can be added before the final else.

1
2
3
4
5
let status;

if(length == 10) {
    status = "full";
}
1
2
3
4
5
6
7
let status;

if(length == 10) {
    status = "full";
} else {
    status = "OK";
}
1
const status = length == 10 ? "full" : "OK";

The ternary operator is often useful as a shorthand conditional statement.

9

Switch statements

switch statements are good when there are many options.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
switch(x) {
  case 1:
    console.log("x is 1");
    break;
  case 2:
    console.log("x is 2");
    break;
  case 3:
    console.log("x is 3");
    break;
  default:
    console.log("x is something else");
}

Be careful though, execution will pass through all the subsequent options unless and until you include the break statement.

10

Basic loops

Repeating code multiple times.

Similar to Java or C, for loops allow things to be repeated a number of times.

1
2
3
4
5
6
// The classic loop style is very efficient and can be useful
// You should probably only use when looping over *huge* ranges

for(let i=0; i<10; i++) {
    console.log(i);
}

A while loop will only execute while a condition is met.

1
2
3
4
5
6
s = "hello world"

// the block is never executed
while(s.length < 10) {
  s = `${s}!` 
}

A do…while loop will always execute once before the condition is checked.

1
2
3
4
5
6
s = "hello world"

// we add one exclamation mark and the condition fails first time
do {
  s = `${s}!`             
} while (s.length < 10) 
11

Functions

Functions can help to avoid repetition and make code more readable and more maintainable.

the function keyword is followed by a comma-separated argument list in parentheses and a code block with an optional return statement.

1
2
3
4
5
// The classic form is absolutely fine

function randomBetween(min, max) {
  return min + Math.random() * (max - min);
}

A newer syntax (ECMAScript 2015) for more compact functions using arrow (=>) notation.

1
2
3
4
5
6
// Arrow functions are more explicitly treated as normal data
// They are essentially identical, though have some restrictions 

const randomBetween = (min, max) => {
  return min + Math.random() * (max - min);
}

Simple one-line arrow functions can be very compact.

1
2
3
4
5
// the return statement can be implicit for a one-line function
const randomBetween = (min, max) => min + Math.random() * (max - min);

// Parentheses are not needed when there is exactly one argument 
const doubleIt = value => value * 2;
12

Arrays

Arrays are ordered collections of data.

Create them using square bracket notation, they can contain anything.

1
2
const tech = ["HTML", "CSS"];
tech.length;        // 2

They are indexed with integers (beginning with zero).

1
2
tech[0];            // "HTML"
tech[1];            // "CSS"

Or use the at method which also allows negative indices, counting from the end at -1.

1
2
tech.at(1)      // "CSS"
tech.at(-1)     // "CSS"

They have built-in methods for basic mutations.

1
2
3
4
tech.push("JS");    // add to the end - ["HTML", "CSS", "JS"]
tech.pop();         // remove from the end - ["HTML", "CSS"]
tech.unshift("JS")  // add to the start - ["JS", "HTML", "CSS"]
tech.shift()        // remove from the start - ["HTML", "CSS"]
13

More array methods

Some really useful methods of the Array class take callback functions as the main argument. This is a powerful tool when more complex transformations are needed.

forEach simply executes the callback for each element.

1
2
3
4
5
6
const doSomething = item => console.log(item.toUpperCase());
const numbers = ['one', 'two', 'three'];
numbers.forEach(doSomething);
// ONE
// TWO
// THREE

filter will return a new Array including only those elements that return true when passed through the provided function.

1
2
3
4
const lengthThree = item => item.length == 3;
const originals = ['one', 'two', 'three', 'four', 'five', 'six'];
const filtered = originals.filter(lengthThree); 
// ['one', 'two', 'six']

map Returns a new Array in which each element has been converted by the provided function.

1
2
3
4
const transformItem = item => `${item.toUpperCase()}!!!`;
const originals = ['one', 'two', 'three']
const transformed = originals.map(transformItem);   
// ['ONE!!!', 'TWO!!!', 'THREE!!!']
14

Looping over iterables

Built-in iterables such as String and Array follow the iterable protocol. This allows them to define a sequence which can be iterated using a for...of loop.

1
2
3
4
5
6
7
8
                                              // "Gimme a 'C'!
const code = "CTEC3705";                      // "Gimme a 'T'!
                                              // "Gimme a 'E'!
for (const character of code) {               // "Gimme a 'C'!
    console.log(`Gimme a '${character}'!`);   // "Gimme a '3'!
}                                             // "Gimme a '7'!
                                              // "Gimme a '0'!
                                              // "Gimme a '5'!

Example with an Array

1
2
3
4
5
const technologies = ["HTML", "CSS", "JS"];

for (const technology of technologies) {    // "learn HTML!"
    console.log(`learn ${technology}!`);    // "learn CSS!"
}                                           // "learn JS!"

This is a great way to iterate over things like elements extracted from the DOM.

15

Object literals

Objects can be treated as key/value pairs. Though they are far more than that.

Objects are defined with curly braces containing comma-separated key/value pairs. Each key/value pair is separated with a colon.

1
2
3
4
myObject = {
    key1: "value",
    key2: 12
};

They can be modified using square bracket notation.

1
2
3
4
5
// Reading and writing properties

const oldValue = myObject["key1"]; 
myObject["key1"] = "new value";
myObject["new key"] = false;

Though dot notation is more convenient, it is limited (e.g. no spaces in keys).

1
2
3
4
5
// try to access a proporty that hasn't been defined
console.log(myObject.missingValue); // undefined

// Add new properties
myObject.missingValue = "no longer missing";

for...in loops iterate over the key values. This is the same for arrays (where the keys are integers).

1
2
3
4
for(const key in myObject) {
    console.log(`${key}: ${myObject[key]}`);
}
// Try console.table(myObject) instead!
16

Maps

A map is an object type which holds key-value pairs. It is often more efficient than an object.

Create a map with the new keyword and use the set() method to store values against keys.

1
2
3
4
5
const myMap = new Map();

myMap.set('HTML', 'declarative');
myMap.set('CSS', 'declarative');
myMap.set('JavaScript', 'imperative');

Extract values using the get() method.

1
console.log(myMap.get('CSS'));

Map objects are iterable, yielding key-value pairs.

1
2
3
for (const [key, value] of myMap) {
  console.log(`${key} = ${value}`);
}

Test if items exist with the has() method.

1
myMap.has('CSS');

Remove items with the delete() method.

1
myMap.delete('CSS');

Remove all items with the clear() method.

1
myMap.clear();
17

web APIs

Web APIs are defined by W3C/WHATWG as standard interfaces built on top of the ECMAScript core language.

The URL API allows us to conveniently and accurately parse data from the URL

1
2
3
4
5
const url = new URL("https://www.dmu.ac.uk/study/courses/courses.aspx");

console.log(url.protocol) // https:
console.log(url.host)     // www.dmu.ac.uk
console.log(url.pathname) // /study/courses/courses.aspx

With the Headers and Response APIs we can create HTTP responses with custom content, headers and status code.

1
2
3
4
5
6
7
8
9
const content = `
<!doctype html>
<html>
    <head><title>My App</title></head>
    <body><h1>hello world</h1></body>
</html>`
const headers = new Headers({"content-type": "text/html"});
const status = 200
const response = new Response(content, {headers, status});

Browsers and JavaScript runtimes implement these APIs.

18

Deno

Deno is a modern (2018) open-source, standards-compliant runtime environment for executing JavaScript without a web browser.

Ryan Dahl

1
2
3
4
5
6
7
// Run a web server by passing a server function to the non-standard Deno.serve API

Deno.serve(server)

// A server function
// - accepts a request object as an argument (here we are extracting the url from the request)
// - always returns a response object (in this case, we have two different responses)

New Deno logo

1
2
3
4
5
6
7
function server(request) {
    const url = new URL(request.url);
    const headers = new Headers();
    headers.set("content-type", "text/html");
    if(url.pathname == "/") return new Response("<h1>Home page</h1>", { headers });
    return new Response("<h1>Not found</h1>", { headers, status: 404 })
}

Deno was created by Ryan Dahl as a response to his Node.js design regrets, .

19

Introducing JavaScript

If you have any questions, now is a good time to ask.

Thanks for listening
Dr Graeme Stuart