During the course along with web development we have a goal and need to learn a sufficient amount of Javascript.

Javascript has advanced rapidly the last few year and in this course we are using features from the newer versions. The official name of the Javascript standard is ECMAScript. At this moment the latest version is the one released in June of 2017 with the name ES9, otherwise known as ECMAScript 2018.

Browsers do not yet support all of Javascript's newest features. Due to this fact a lot of code run in browsers has been transpiled from a newer version of Javascript to an older, more compatible version.

Today's leading way to do the transpiling is using Babel. Transpilation is automatically configured in React applications created with create-react-app. We will take a closer look at the configuration of the transpilation in part 7 of this course.

Node.js is a Javascript runtime environment based on Google's chrome V8 Javascript engine and works practically anywhere from servers to mobile phones. Let's practice writing some Javascript using Node. It is expected that the version of Node.js installed on your machine is at least version v8.10.0. The latest verisons of Node already understand the latest versions of Javascript, so the code does not need to be transpiled.

The code is written into files ending with .js and are run by issuing the command node nameoffile.js

It is also possible to write Javascript code into the Node.js console, which is opened by typing node in the command-line, as well as into the browser's developer tool console. The newest revisions of Chrome handle the newer features of Javascript pretty well without transpiling the code.

Javascript is sort of reminiscent both in name and syntax to Java. But when it comes to core mechanism of the language they could not be more different. Coming from a Java background the behavior of Javascript can seem a bit alien, especially if one cannot bother to look up the features of the language.

In certain circles it has also been popular to attempt "simulating" Java features and design patterns in Javascript. I do not recommend doing this.

Variables

In Javascript there are a few way to go about defining variables:

const x = 1
let y = 5

console.log(x, y)   // tulostuu 1, 5
y += 10
console.log(x, y)   // tulostuu 1, 15
y = 'teksti'
console.log(x, y)   // tulostuu 1, teksti
x = 4               // aiheuttaa virheen

const does not actually define a variable but a constant for which the value can no longer be changed. On the other hand let defines a normal variable.

In the example we also see that the type of the data assigned to the variable can change during execution. At the start y stores an integer and at the end a string.

It is also possible to define variables in Javascript using the keyword var. Var was for a long time the only way to define variables. Const and let were only recently added in version ES6. In specific situations var work in a different way compared to variable definitions in most languages. During this course the use of var is ill advised and you should stick with using const or let!

You can find more on this topic on e.g. YouTube - var, let and const - ES6 JavaScript Features

Arrays

An array and a couple of examples of its use

const t = [1, -1, 3]

t.push(5)

console.log(t.length) // tulostuu 4
console.log(t[1])     // tulostuu -1

t.forEach(value => {
  console.log(value)  // tulostuu 1, -1, 3, 5 omille riveilleen
})                    

Notable in this example is the fact that the contents of the array can be modified even though it is defined as a const. Because the array is an object the variable always points to the same object. The content of the array changes as new items are added to it.

One way of iterating through the items of the array is using forEach as seen in the example. forEach receives a function defined using the arrow syntax as a parameter.

value => {
  console.log(value)
}

forEach calls the function for each of the items in the array always passing the individual item as a parameter. The function as the parameter of forEach may also receive other parameters.

In the previous example a new item was added to the array using the method push. When using React, techniques from functional programming are often used. One characteristic of the functional programming paradigm is the use of immutable data structures. In React code it is preferable to use the method concat, which does not add the item to the array, but creates a new array in which the content of the old array as well as the new item is included.

const t = [1, -1, 3]

const t2 = t.concat(5)

console.log(t)  // tulostuu [1, -1, 3]
console.log(t2) // tulostuu [1, -1, 3, 5]

The method call t.concat(5) does not add a new item to the old array, but returns a new array, which besides containing the items of the old array also contains the new item.

There are plenty of useful methods defined for arrays. Let's look at a short example of using the map method.

const t = [1, 2, 3]

const m1 = t.map(value => value * 2)
console.log(m1)   // tulostuu [2, 4, 6]

Based on the old array, map creates a new array, for which the function given as a parameter is used to create the items, in the case of this example the original value is multiplied by two.

Map can also transform the array into something completely different:

const m2 = t.map(value => '<li>' + value + '</li>')
console.log(m2)  
// tulostuu [ '<li>1</li>', '<li>2</li>', '<li>3</li>' ]

Here an array filled with integer values is transformed into an array containing HTML using the map method. In part2 of this course we will see that map is used quite frequently in React.

Individual items of an array are easy to assign to variables with the help of destructuring assignment.

const t = [1, 2, 3, 4, 5]

const [first, second, ...rest] = t

console.log(first, second)  // tulostuu 1, 2
console.log(rest)           // tulostuu [3, 4 ,5]

Thanks to the assignment the variables first and second will receive the first two integers of the array as their values. The remaining integers are "collected" into an array of their own, which is then assigned to the variable rest.

Objects

There are a few different ways of defining objects in Javascript. A very commonly used method is using object literals, which happens by listing its properties within braces:

const object1 = {
  name: 'Arto Hellas',
  age: 35,
  education: 'Filosofian tohtori',
}

const object12 = {
  name: 'Full Stack -websovelluskehitys',
  level: 'aineopinto',
  size: 5,
}

const object3 = {
  name: {
    first: 'Juha',
    last: 'Tauriainen',
  },
  grades: [2, 3, 5, 3],
  department: 'TKTL',
}

The values of the properties can be of any type, like integers, strings, arrays, objects...

The properties of an object are referenced by using dot notation, or using brackets:

console.log(object1.name)         // tulostuu Arto Hellas
const fieldName = 'age' 
console.log(object1[fieldName])   // tulostuu 35

You can also add properties to an object on the fly by either using dot notation or using brackets:

object1.address = 'Tapiola'
object1['secred number'] = 12341

The latter of the additions has to be done by using brackets, because when using dot notation secred number is not a valid property name.

Naturally, objects in Javascript can also have methods. However, during this course we will not be defining any objects with methods of our own. This is why it only discussed briefly.

Objects can also be defined using so-called constructor functions, which results in a mechanism reminiscent of many other programming languages', e.g. Java's classes. Despite this similarity Javascript does not have classes in the same sense as object oriented programming languages. There has been, however, an addition of the class syntax starting from version ES6, which in some cases helps structure object oriented classes.

Functions

We have already become familiar with defining so-called arrow functions. The complete process, without cutting corners, to defining an arrow function is as follows

const sum = (p1, p2) => {
  console.log(p1)
  console.log(p2)
  return p1 + p2
}

and the function is called as can be expected

const result = sum(1, 5)
console.log(result)

If there is just a single parameter we can exclude the parentheses from the definition:

const square = p => {
  console.log(p)
  return p * p
}

If the function only contains a single expression, then the braces are not needed. In this case the function only returns the result its only expression. Now if we remove the printing to the console, we can further shorten the function definition:

const square = p => p * p

This form is particularly handy when manipulating arrays, e.g using the map method:

const t = [1, 2, 3]
const tSquared = t.map(p => p * p)
// tSquared on nyt [1, 4, 9]

The arrow function was added to Javascript only a couple of years ago along with version ES6. Prior to this the only way to define functions was by using the keyword function.

There are two ways, of which one is giving a name in a so-called function declaration to the function, by which the function can be referenced.

function product(a, b) {
  return a * b
}

const vastaus = product(2, 6)

The other way to do the define the function is as a function expression. In this case there is no need to give the function a name, and the definition may reside among the rest of the code:

const average = function(a, b) {
  return (a + b) / 2
}

const vastaus = average(2, 5)

During this course we will define all functions using the arrow syntax.

Object methods and this

Due to the fact that during this course we are using a version of React containing React hooks, we have no need for defining objects with methods. The contents of this chapter are not relevant to the course, but are certainly in many ways good to know. In particular when using older versions of React one must understand the topics of this chapter.

Arrow functions and functions defined using the function keyword vary substantially when it comes to how they behave with respect to the keyword this, which refers to the object itself.

We can assign methods to object by defining properties that are functions:

const arto = {
  name: 'Arto Hellas',
  age: 35,
  education: 'Filosofian tohtori',
  greet: function() {
    console.log('hello, my name is', this.name)
  },
}

arto.greet()  // tulostuu hello, my name is Arto Hellas

methods can be assigned to objects even after the creation of the object:

const arto = {
  name: 'Arto Hellas',
  age: 35,
  education: 'Filosofian tohtori',
  greet: function() {
    console.log('hello, my name is', this.name)
  },
}

arto.growOlder = function() {  this.age += 1}
console.log(arto.age)   // tulostuu 35
arto.growOlder()
console.log(arto.age)   // tulostuu 36

Let's slightly modify the object

const arto = {
  name: 'Arto Hellas',
  age: 35,
  education: 'Filosofian tohtori',
  greet: function() {
    console.log('hello, my name is', this.name)
  },
  doAddition: function(a, b) {    console.log(a + b)  },}

arto.doAddition(1, 4) // tulostuu 5

const referenceToAdditon = arto.doAddition
referenceToAdditon(10, 15) // tulostuu 25

Now the object has a method doAddition, which calculates the sum of numbers given to it as parameters. The method is called in the usual way using the object arto.doAddition(1, 4) or by storing a method reference in a variable and calling the method through the variable referenceToAdditon(10, 15).

If we try to do the same thing with the method greet we run an issue:

arto.greet()       // tulostuu hello, my name is Arto Hellas

const referenceToGreet = arto.greet
referenceToGreet() // konsoliin tulostuu virheilmoitus

When calling the method through a reference the method has lost the information on what was the original this. Contrary to other languages, in Javascript the value of this is defined based on how the method is called. When calling the method through a reference the value of this becomes the so-called global object and the end result is often not what the software developer intended.

Losing track of this when writing Javascript code brings forth a few potential issues. Situations often arise where React's or Node's (or more specifically the Javascript engine of the web browser) needs to call some method in an object that the developer has defined. However, in this course we are spared from the issues, since we are only using the "thisless" Javascript.

One situation leading to the disappearance of this arises when, e.g. we ask Arto to greet in one second using the setTimeout method.

const arto = {
  name: 'Arto Hellas',
  greet: function() {
    console.log('hello, my name is', this.name)
  },
}

setTimeout(arto.greet, 1000)

The value of this in Javascript is defined based on how the method is being called. When setTimeout is using the method it is the Javascript engine that calls the method and this refers to the Timeout object.

There are several mechanism by which the original this can be preserved. One of these is using a method called bind:

setTimeout(arto.greet.bind(arto), 1000)

The command arto.greet.bind(arto) creates a new function, where it has bound this to point to Arto independent of where and how the method is being called.

Using arrow functions it is possible to solve some of the problems related to this. They should not, however, be used as methods for objects because then this does not work at all. We will come back to the behavior of this in relation to arrow functions later.

If you want to gain a better understanding of how this works in Javascript the internet is full of material about the topic, e.g. the screen cast series Understand JavaScript's this Keyword in Depth by egghead.io is highly recommended!

Classes

As mentioned previously, there is no class mechanism like ones in object oriented programming languages. There are, however, features in Javascript which makes "simulating" object oriented classes possible.

Let's take a quick look at the class syntax that was introduced into Javascript along with ES6, which substantially simplifies the definition of classes (or class like things) in Javascript.

Coming up we have defined a "class" called Person and two Person objects.

class Person {
  constructor(name, age) {
    this.name = name
    this.age = age
  }
  greet() {
    console.log('hello, my name is', this.name)
  }
}

const arto = new Person('Arto Hellas', 35)
arto.greet()

const juhq = new Person('Juha Tauriainen', 48)
juhq.greet()

When it comes to syntax the classes and the objects created from them are very reminiscent of e.g. Java classes and objects. Their behavior is also quite similar to Java objects. At the core they are still objects based on Javascript's prototype inheritance. The type of both objects is actually Object since Javascript essentially only has the types Boolean, Null, Undefined, Number, String, Symbol ja Object.

Introduction of the class syntax is a controversial addition, e.g. check out Not Awesome: ES6 Classes or Is “Class” In ES6 The New “Bad” Part?

The ES6 class syntax is used a lot in the "old" React and in Node.js and therefore understanding it is beneficial even on this course. Because we are using the new hook feature of React during this course we have no need to use the class syntax of Javascript.

Javascript materials

On the internet we can find both good and bad guides for Javascript. On this page most of the links relating to Javascript features link to Mozilla's Javascript Guide.

It is highly recommended to immediately read A re-introduction to JavaScript (JS tutorial) on Mozillas website.

If you wish to deeply get to know Javascript there is a great free book series on the internet called You-Dont-Know-JS.

egghead.io has plenty of quality screencasts on Javascript, React, and other interesting topics. Unfortunately some of the material is behind a paywall.