ES6 javascript refresher
September 30, 2020
var, let and const - what’s the difference
Before ES6 we had the var
keyword to declare variables. The variables declared with var are function scoped.
The scope is global when a var
variable is declared outside a function. It means that variables declared with var
outside of a function is accessible, visible and available for use in the global scope (e.g.: the whole window).
var
declared variables has a function scope when they are declared within a given function. It means that they are available and can be accessed within that given function.
Variables declared with var can be re-declared and updated
var number = 0;
var number = 1;
{
var number = 2;
}
console.log(number);
This is perfectly legal and the output is: 2
. And it is a problem! Think of a bigger program when you forget that you already declared number and you re-declare it. You immediately set yourself up for a nice series of bugs.
let to the rescue
After ES6 let is the preferred way of declaring variables, in case we expect the variables’ values to change. let has block (bracket) scope and that immediately solves the problem we have just seen above in case of var.
Variables declared with let can be updated.
let number = 0;
// re-declaring number again in the same scope would generate an error message, so we can't do the below
// let number = 1;
number = 100;
{
let number = 2;
}
console.log(number);
As you would guess the output is now: 100
Always try to be strict, use const when possible
Good progrmming principle is to be as trict as possible with regards to allowing data changes. As discussed let will allow you to update the variables’ value during the course of the program execution and this is a perfectly legit scenario. However, most of the times (believe me) you will not need to change the value of that variable. In such cases we should be stricter. Use const.
const will not allow reassignment of values.
const number = 100;
// this would fail: TypeError: Assignment to constant variable.
// number = 200;
const array = [1, 2, 3, 4, 5];
// this is legal, as we are not changing the assignment of our array variable, it still point at the same object
array.push(6);
// however this would again generate an error message: TypeError: Assignment to constant variable.
// array = [100, 101, 102];
Arrow functions
Before ES6 we used classic functions using the function keyword.
function callMyName(name) {
console.log(name);
}
callMyName("Tomi");
ES6 provided us with arrow functions.
callMyName = name => console.log(`Hello ${name}`);
callMyName("Tomi");
Did you notice that I used a template literal? Between the ` (backticks) I used ${} to print a value of the name parameter. This is a more elegant way than concatenating strings with +.
If your arrow function requires more parameters or the function body consists of more than one commands the arrow functions syntax changes slightly adding extra brackets, curly brackets.
callMyName = (salutation, name) => {
console.log(`${salutation} ${name}`);
return true;
};
callMyName("Hello", "Tomi");
foreach loop
Easy looping thru collections with foreach.
const family = ["mom", "dad", "daughter", "son"];
family.forEach((member, index) => console.log(`${index + 1}. ${member}`));
output:
1. mom
2. dad
3. daughter
4. son
map is to manipulate collections
map is similar to foreEach with the addition of returning a new collection (e.g.: array) of modified collection elements. Let’s use the previously declared family array and capitalize all members of it.
const family = ["mom", "dad", "daughter", "son"];
const capitalizedFamily = family.map(
(member) => member.charAt(0).toUpperCase() + member.slice(1)
);
capitalizedFamily.forEach((member) => console.log(`${member}`));
Our output is:
Mom
Dad
Daughter
Son
filter to apply filters to collections
Again, another method that works on collections and as the name suggests, it’s used for filtering out elements from a collection, e.g.: from an array. The syntax is similar to map, we pass an arrow function to filter that gets the actual element of the collection to be cheked and we must return a boolean value, whether or not we want to filter out the passed item. Here is an example where we want to filter out dad:
const family = ["mom", "dad", "daughter", "son"];
console.log(family.filter((member) => member != "dad"));
The filtered output
["mom", "daughter", "son"]
The spread operation aka three dots …
As per MDN Web Docs
Spread syntax (…) allows an iterable such as an array expression or string to be expanded in places where zero or more arguments (for function calls) or elements (for array literals) are expected, or an object expression to be expanded in places where zero or more key-value pairs (for object literals) are expected.
Better to explain thru an example:
const family = ["mom", "dad", "daughter", "son"];
const anotherFamily = [...family, "aunt"];
console.log(anotherFamily);
The output is:
["mom", "dad", "daughter", "son", "aunt"]
Let’s do the same with an object:
const car = {
type: "BMW",
model: "X5",
};
const expandedCar = {
...car,
engine: "30d",
};
console.log(expandedCar);
The output is:
{type: "BMW", model: "X5", engine: "30d"}
Destructuring - picking attributes or elements from an object or an array
Sometimes we only need some parts or attributes from an object or from an array, here is the desctructuring assignment to the rescue:
const family = ["mom", "dad", "daughter", "son"];
let [female, male] = family;
console.log(female, male);
and the output:
mom dad
Note that we used a square bracket syntax after the let and we extracted (destructured) the first two elements from the family array into variables female and male.
Let’s do something similar with objects:
const car = {
type: "BMW",
model: "X5",
options: ["leather seats", "tempomat", "rear seat heating"],
engine: {
ccm: 3000,
type: "I6",
},
};
let { model, engine } = car;
console.log(model, engine);
and the output:
X5 {ccm: 3000, type: "I6"}
For object destructuring we used the curly braces syntax.
Classes, subclasses in ES6
Nothing fancy, just simple plain OO in javascript, here is how to declare a class, create instance variables and methods.
class Car {
constructor(type, model) {
this.type = type;
this.model = model;
}
printCar() {
console.log(`${this.type} ${this.model}`);
}
}
new Car("BMW", "X5").printCar();
new Car("Audi", "R8").printCar();
This produces an output of:
BMW X5
Audi R8
Subclassing, use the extends keyword
As usual, we can extend classes by using the extends keyword. Here is a simple example:
class ElectricCar extends Car {
constructor(type, model, range) {
super(type, model);
this.range = range;
}
printCar() {
super.printCar();
console.log(`It has ${this.range} km range.`);
}
}
new ElectricCar("VW", "ID3", "350").printCar();
Prints out the following:
VW ID3
It has 350 km range.