Basic JavaScript ES6

Basic JavaScript ES6

by John Vincent


Posted on February 24, 2017



Basic JavaScript ES6

Lets discuss with examples.

JavaScript ES6 / ES2015

ES6 Compatibility Table

ES6 in Depth Articles

Contents


Let and Const

Instead of var, use let and const

// ES5
var name5 = 'Jane Smith';
var age5 = 23;
name5 = 'Jane Miller';
console.log(name5);

// ES6
const name6 = 'Jane Smith';
let age6 = 23;
name6 = 'Jane Miller';
console.log(name6);

Variables defined with var are function scoped.

Variables defined with let and const are block scoped

// ES5
function driversLicence5(passedTest) {

    if (passedTest) {
        console.log(firstName);
        var firstName = 'Pete';
        var yearOfBirth = 1995;
    }
    console.log("driversLicence5; " + firstName + ', born in ' + yearOfBirth + ', is now officially allowed to drive a car.');
}

driversLicence5(true);

// ES6
function driversLicence6(passedTest) {
    //console.log(firstName);
    let firstName;
    const yearOfBirth = 1990;
    if (passedTest) {
        firstName = 'John';
    }
    console.log("driversLicence6; " + firstName + ', born in ' + yearOfBirth + ', is now officially allowed to drive a car.');
}

driversLicence6(true);

Another example

let i = 23;

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

console.log("after loop " + i);

which produces

0
1
2
3
4
after loop 23

as let is block scoped


Loops

for of loops

Introduced for ES6, addresses all of the major issues with for in loops

Iterating over an Array

let iterable = [2, 4, 7];
for (const value of iterable) {	// 2, 4, 7
  console.log(value);
}

Iterating over a String

let iterable = 'abc';
for (const value of iterable) {	// 'a', 'b', 'c'
  console.log(value);
}

Iterating over a Map

let iterable = new Map([['a', 1], ['b', 2], ['c', 3]]);
for (const entry of iterable) {	// ['a', 1], ['b', 2], ['c', 3]
  console.log(entry);
}

for (let [key, value] of iterable) {		// 1, 2, 3
  console.log(value);
}

Iterating over a Set

let iterable = new Set([1, 1, 2, 2, 3, 3]);
for (let value of iterable) {
  console.log(value);	// 1, 2, 3
}

Iterating over arguments object

(function() {
  for (let argument of arguments) {
    console.log(argument);			// 1, 2, 3
  }
})(1, 2, 3);

for() loop

Loops allow you to iterate over collections and objects.

for (let i = 0; i < 4; i++) {	// 0,1,2,3
  console.log(i);
}

for in loops

loops also iterate tgrough properties of an object. Use with objects where index order isn’t important.

let obj = {"alpha":0, "beta":20};

for (let i in obj) {	// alpha, beta
  console.log(i);
}

Array.forEach()

let arr = [2,4,7];
arr.forEach((i) => {	// 2, 4, 7
  console.log(i);
})

while loops

let i = 0
while(i < 4) {		// 0, 1, 2, 3
  console.log(i);
  i++;
}

do while loops

let i = 0
do {					// 0, 1, 2, 3
  console.log(i);
  i++;
} while(i < 4) {		


Blocks and IIFEs

// ES5
(function() {
    var c = 3;
})();

console.log(c);

which produces an error, as var c = 3 is not accessible outside of the IIFE.

// ES6
{
    const a = 1;
    let b = 2;
    var c = 5;
    console.log(a + b);
}

//console.log(a + b);		// would error
console.log(c);

which produces

3
5

as var c = 5; is function scoped.


Strings

let firstName = 'John';
let lastName = 'Smith';
const yearOfBirth = 1990;

function calcAge(year) {
    return 2016 - year;
}

// ES5
console.log('This is ' + firstName + ' ' + lastName + '. He was born in ' + yearOfBirth + '. Today, he is ' + calcAge(yearOfBirth) + ' years old.');

// ES6
console.log(`This is ${firstName} ${lastName}. He was born in ${yearOfBirth}. Today, he is ${calcAge(yearOfBirth)} years old.`);

const n = `${firstName} ${lastName}`;
console.log(n.startsWith('j'));
console.log(n.endsWith('Sm'));
console.log(n.includes('oh'));
console.log(`${firstName} `.repeat(5));


Arrow Functions

const years = [1990, 1965, 1982, 1937];

// ES5
var ages5 = years.map(function(el) {
    return 2016 - el;
});
console.log("ages5 "+ages5);


// ES6

// one parameter
let ages6 = years.map(el => 2016 - el);
console.log("(1) ages6 "+ages6);

// two parameters
ages6 = years.map((el, index) => `Age element ${index + 1}: ${2016 - el}.`);
console.log("(2) ages6 "+ages6);

// two parameters, multi lines of code in the function
ages6 = years.map((el, index) => {
    const now = new Date().getFullYear();
    const age = now - el;
    return `Age element ${index + 1}: ${age}.`;     // return explicitly stated
});
console.log("(3) ages6 "+ages6);

ES5

function Person(name) {
    this.name = name;
}

Person.prototype.myFriends5 = function(friends) {

    var arr = friends.map(function(el) {
       return this.name + ' is friends with ' + el;
    }.bind(this));

    console.log(arr);
};

var friends = ['Bob', 'Jane', 'Mark'];
new Person('John').myFriends5(friends);

ES6

function Person(name) {
    this.name = name;
}

Person.prototype.myFriends6 = function(friends) {

    var arr = friends.map(el => `${this.name} is friends with ${el}`);

    console.log(arr);
};

var friends = ['Bob', 'Jane', 'Mark'];
new Person('Mike').myFriends6(friends);


Arrow Function this keyword

In ES6, arrow functions do not have a this keyword.

In ES6, arrow function shares the this keyword with the surrounding function.

ES5, this refers to the window object.

var box5 = {
    color: 'green',
    position: 1,
    clickMe: function() {
        var self = this;
        document.querySelector('.green').addEventListener('click', function() {
            var str = 'This is box number ' + self.position + ' and it is ' + self.color;
            alert(str);
        });
    }
};
box5.clickMe();

ES6, this refers to calling object

const box6 = {
    color: 'green',
    position: 1,
    clickMe: function() {
        document.querySelector('.green').addEventListener('click', () => {
            var str = 'This is box number ' + this.position + ' and it is ' + this.color;
            alert(str);
        });
    }
};
box6.clickMe();

In this example, use of 2 arrow functions causes this to be global

// this is from the global object.
const box66 = {
    color: 'green',
    position: 1,
    clickMe: () => {
        document.querySelector('.green').addEventListener('click', () => {
            var str = 'This is box number ' + this.position + ' and it is ' + this.color;
            alert(str);
        });
    }
};
box66.clickMe();

Example

const fakeTitles = [
  'Pirate Of Reality',
  'Guardians Of Hell',
  'Witches With Vigor',
  'Spies And Heroes',
  'Robots And Kings',
];

const abbreviations = fakeTitles.map(
  title => title.toLowerCase().slice(0, 3));

// equivalent using non-arrow functions
const abbreviationsEs5 = fakeTitles.map(function(title) { return title.toLowerCase().slice(0, 3); });

console.log(abbreviations); // ['pir', 'gua', 'wit', 'spi', 'rob']

Note that the arrow function syntax can vary, depending on how many parameters the function takes

const items = ['milk', 'bread', 'eggs', 'oranges'];

// when no parameters
items.forEach(() => console.log('another item'));

// when one parameter, the parentheses are optional
items.forEach((item) => console.log(item));
items.forEach(item => console.log(item));

// when more than one parameter
items.forEach((item, index) => console.log('Index ' + index + ' is: ' + item));


Object Destructuring

Destructuring assignment is a new way of assigning values contained in objects and arrays to new variables.

ES5

var john = ['John', 26];
var name = john[0];
var age = john[1];

ES6

const [name, age] = ['John', 26];
console.log(name);
console.log(age);

ES6

const obj = {
    firstName: 'John',
    lastName: 'Smith'
};

const {firstName, lastName} = obj;
console.log(firstName);
console.log(lastName);

const {firstName: a, lastName: b} = obj;
console.log(a);
console.log(b);

ES6

function calcAgeRetirement(year) {
    const age = new Date().getFullYear() - year;
    return [age, 65 - age];
}

const [age2, retirement] = calcAgeRetirement(1990);
console.log(age2);
console.log(retirement);

ES6

const myObj = {a: 'apple', b: 'bumblebee', c: 'cat'}
const {a, c} = myObj;				// destructuring
console.log(a); // => apple
console.log(c); // => cat


Property value

This is a convenient shorthand you can use when you need to create an object literal out of a set of variables, and you want to map variable names to keys. It is essentially the inverse of object destructuring.

ES6

const x = 1;
const y = 2;
const myObj = {x, y};

console.log(myObj);

produces

{ x: 1, y: 2 }


Spread

  • is a convenient way to expand elements of an array.
  • provides a compact way to apply parameters to functions.

ES5

function addFourAges (a, b, c, d) {
    return a + b + c + d;
}

var sum1 = addFourAges(18, 30, 12, 21);
console.log("sum1 "+sum1);

var ages = [18, 30, 12, 21];
var sum2 = addFourAges.apply(null, ages);
console.log("sum2 "+sum2);

ES6

function addFourAges (a, b, c, d) {
    return a + b + c + d;
}

var ages = [18, 30, 12, 21];
const sum3 = addFourAges(...ages);      // literally spreads the parameters
console.log("sum3 "+sum3);

ES6

const familySmith = ['John', 'Jane', 'Mark'];
const familyMiller = ['Mary', 'Bob', 'Ann'];
const bigFamily = [...familySmith, 'Lily', ...familyMiller];
console.log(bigFamily);
const h = document.querySelector('h1');
const boxes = document.querySelectorAll('.box');
const all = [h, ...boxes];

Array.from(all).forEach(cur => cur.style.color = 'purple');
function calcVolume(width, height, depth) {
    return width * height * depth;
}
let values = [10, 20, 30];
console.log(calcVolume(...values)); // => 6000


Object Assign

The Object.assign method helps us manage merging objects. Properties from objects passed as the second, third, fourth, etc. arguments are merged into the object passed as the first argument.

ES6

const objA = {
  foo: 'foo',
  bar: 'bar'
};

const objB = {
  foo: 'something else',
  bizz: 'bizz',
  bang: 'bang'
};

// merges params 2-n into param 1
console.log(Object.assign({}, objA, objB));

produces

'{ foo: 'something else', bar: 'bar', bizz: 'bizz', bang: 'bang' }


Modules

Modules allow you to split your code into multiple files, exporting objects from one file and importing them into another. Each module provides a single object for importing, which you can destructure to access the individual variables which were exported. For example:

// file_a.js
export const width = 10;
export const height = 5;
// file_b.js
import {width, height} from './file_a';
console.log(width, height);
// file_b.js
import {width as tableWidth, height as tableHeight} from './file_a';
console.log(tableWidth, tableHeight);
// file_b.js
import * as dimensions from './file_a';
console.log(dimensions.width, dimensions.height);

Each module can also export a single variable called default, which has a corresponding shorthand syntax for importing:

// file_a.js
export default function area(width, height) {
    return width * height;
}
// file_b.js
// Shorthand
import area from './file_a';
// Long version
import {default as area} from './file_a';

The default export is generally used to export the most important variable from a module. Notice how you don’t need to destructure to access the default export.


Classes

ES5

var Person5 = function(name, yearOfBirth, job) {
    this.name = name;
    this.yearOfBirth = yearOfBirth;
    this.job = job;
};

Person5.prototype.calculateAge = function() {
    var age = new Date().getFullYear - this.yearOfBirth;
    console.log(age);
};

var john5 = new Person5('John', 1990, 'teacher');

ES6

class Person6 {
    constructor(name, yearOfBirth, job) {
        this.name = name;
        this.yearOfBirth = yearOfBirth;
        this.job = job;
    }

    calculateAge() {
        var age = new Date().getFullYear() - this.yearOfBirth;
        console.log(age);
    }

    static greeting() {
        console.log('Hey there!');
    }
}

const john6 = new Person6('John', 1990, 'teacher');

Person6.greeting();

john6.calculateAge();

Note that

john6.greeting();

will fail.


Subclasses

ES5

var Person5 = function(name, yearOfBirth, job) {
    this.name = name;
    this.yearOfBirth = yearOfBirth;
    this.job = job;
};

Person5.prototype.calculateAge = function() {
    var age = new Date().getFullYear() - this.yearOfBirth;
    console.log(age);
};

var Athlete5 = function(name, yearOfBirth, job, olymicGames, medals) {
    Person5.call(this, name, yearOfBirth, job);
    this.olymicGames = olymicGames;
    this.medals = medals;
};

Athlete5.prototype = Object.create(Person5.prototype);


Athlete5.prototype.wonMedal = function() {
    this.medals++;
    console.log(this.medals);
};


var johnAthlete5 = new Athlete5('John', 1990, 'swimmer', 3, 10);

johnAthlete5.calculateAge();
johnAthlete5.wonMedal();

ES6

class Person6 {
    constructor(name, yearOfBirth, job) {
        this.name = name;
        this.yearOfBirth = yearOfBirth;
        this.job = job;
    }

    calculateAge() {
        var age = new Date().getFullYear() - this.yearOfBirth;
        console.log(age);
    }
}

class Athlete6 extends Person6 {
    constructor(name, yearOfBirth, job, olympicGames, medals) {
        super(name, yearOfBirth, job);
        this.olympicGames = olympicGames;
        this.medals = medals;
    }

    wonMedal() {
        this.medals++;
        console.log(this.medals);
    }
}

const johnAthlete6 = new Athlete6('John', 1990, 'swimmer', 3, 10);

johnAthlete6.wonMedal();
johnAthlete6.calculateAge();

Another example

class Dog extends Animal {
    constructor(name, breed) {
        super(name);
        this.breed = breed;
    }

    speak() {
        console.log(`${this.name} barks`);
    }
}

const lassie = new Dog('lassie', 'Rough collie');
lassie.speak(); // lassie barks


Rest parameters

Combines parameters passed to the function into an array.

ES6

function isFullAge6(...years) {
    years.forEach(cur => console.log((2016 - cur) >= 18));
}

isFullAge6(1990, 1999, 1965, 2016, 1987);

ES6

function isFullAge6(limit, ...years) {
    years.forEach(cur => console.log((2016 - cur) >= limit));
}

isFullAge6(16, 1990, 1999, 1965, 2016, 1987);


Default Parameters

ES5, parameters that are not set have a value of undefined

function SmithPerson(firstName, yearOfBirth, lastName, nationality) {

    lastName === undefined ? lastName = 'Smith' : lastName = lastName;
    nationality === undefined ? nationality = 'american' : nationality = nationality;

    this.firstName = firstName;
    this.lastName = lastName;
    this.yearOfBirth = yearOfBirth;
    this.nationality = nationality;
}

ES6

function SmithPerson(firstName, yearOfBirth, lastName = 'Smith', nationality = 'american') {
    this.firstName = firstName;
    this.lastName = lastName;
    this.yearOfBirth = yearOfBirth;
    this.nationality = nationality;
}

var john = new SmithPerson('John', 1990);
var emily = new SmithPerson('Emily', 1983, 'Diaz', 'spanish');


Map

Map is a data collection type in which data is stored in a form of pairs, which contains a unique key and value mapped to that key. And because of the uniqueness of each stored key, there is no duplicate pair stored.

Key-value data structure. The key can be any type, including a function.

The original order of elements is preserved.

Map is an instance of Object.

Examples

const question = new Map();
question.set('question', 'What is the official name of the latest major JavaScript version?');
question.set(1, 'ES5');
question.set(2, 'ES6');
question.set(3, 'ES2015');
question.set(4, 'ES7');
question.set('correct', 3);
question.set(true, 'Correct answer');
question.set(false, 'Wrong, please try again!');

console.log(question.get('question'));
console.log(question.size);


if(question.has(4)) {
    question.delete(4);
    console.log('Answer 4 is here')
}

//question.clear();


question.forEach((value, key) => console.log(`This is ${key}, and it's set to ${value}`));


for (let [key, value] of question.entries()) {
    if (typeof(key) === 'number') {
        console.log(`Answer ${key}: ${value}`);
    }
}

const ans = parseInt(prompt('Write the correct answer'));
console.log(question.get(ans === question.get('correct')));

Iterators

const myMap = new Map();
myMap.set(0, 'zero');
myMap.set(1, 'one');
for (const [key, value] of myMap) {
	console.log(`${key} = ${value}`);
}
// 0 = zero
// 1 = one

for (const key of myMap.keys()) {
	console.log(key);
}
// 0
// 1

for (const value of myMap.values()) {
	console.log(value);
}
// zero
// one

for (const [key, value] of myMap.entries()) {
	console.log(`${key} = ${value}`);
}
const kvArray = [['key1', 'value1'], ['key2', 'value2']];
const myMap = new Map(kvArray);
console.log(Array.from(myMap.keys()));
console.log(Array.from(myMap.values()));

Merge

// map of form [key, value,...]

const map1 = new Map(arr1);
const map2 = new Map(arr2);
const merged = new Map([...map1, ...map2]);

Object

The keys must be simple types, either integer, string or symbols.

The element order is not preserved.

var obj = {}; // Empty object
var obj = {id: 1, name: "Any"}; 

Access

obj.id;
obj['id'];

Check for existamce

const isExist = obj.id === undefined;

const isExist = 'id' in obj;

Iterating

const obj = {id: 1, name: "any"}
for (let key in obj) {
   console.log(`key: ${key}, value: ${obj[key]}`);
   // key: id, value: 1
   // key: name, value: any
}

or

Object.keys(obj).forEach((key)=> console.log(`key: ${key}, value: ${obj[key]}`));
//key: id, value: 1
//key: name, value: test


Array

Array is considered as indexed collection type of data structure ie data is ordered by an index value.

const arr = new Array(5);

length = 5 and elements are undefined.

ES6

const boxes = document.querySelectorAll('.box');

const boxesArr6 = Array.from(boxes);
Array.from(boxes).forEach(cur => cur.style.backgroundColor = 'dodgerblue');

for (const cur of boxesArr6) {
    if (cur.className.includes('blue')) {
        continue;
    }
    cur.textContent = 'I changed to blue!';
}

ES5

var ages = [12, 17, 8, 21, 14, 11];

var full = ages.map(function(cur) {
    return cur >= 18;
});
console.log(full);

console.log(full.indexOf(true));
console.log(ages[full.indexOf(true)]);

ES6

var ages = [12, 17, 8, 21, 14, 11];
console.log(ages.findIndex(cur => cur >= 18));
console.log(ages.find(cur => cur >= 18));

produces

3
21


Array reduce() method

ES5

var data = [
    {"city":"seattle", "state":"WA", "population":652405, "land_area":83.9},
    {"city":"new york", "state":"NY", "population":8405837, "land_area":302.6},
    {"city":"boston", "state":"MA", "population":645966, "land_area":48.3},
    {"city":"kansas city", "state":"MO", "population":467007, "land_area":315}
  ];

var landSum = data.reduce(function(sum, d) {
    return sum + d.land_area;
}, 0);
console.log(landSum);

ES6

class Base {
    constructor(name, built) {
        this.name = name;
        this.built = built;
    }
    calculateAge() {
        var age = new Date().getFullYear() - this.built;
//        console.log("Base::calculateAge; age "+age);
        return age;
    }
}

class Park extends Base {
    constructor (name, built, trees, area) {
        super(name, built);
        this.trees = trees;
        this.area = area;
    }
}

const parks = [
new Park('park-1', 1990, 500, 12000),
new Park('park-2', 1950, 2000, 5000),
new Park('park-3', 1890, 4500, 3000)
];
const total2 = parks.reduce((sum, item) => sum + item.calculateAge(), 0);
console.log("total2 "+total2);
const total = parks.reduce((sum, item) => {
    return sum + item.calculateAge();
}, 0);
console.log("total "+total);

Reverse a string

function reverse(str) {
	if (!str) {
		return str;
	}
	return str.split('').reduce((c, v) => v + c, '');
}

Using Array.forEach()

let total_street_length_2 = 0;
streets.forEach(el => total_street_length_2 += el.length);
console.log(`total_street_length_2 ${total_street_length_2}`);

Using Array.every()

The every() method tests whether all elements in the array pass the test implemented by the provided function. It returns a Boolean value.

function isBelowThreshold(currentValue) {
  return currentValue < 40;
}

const arr = [1, 30, 39, 29, 10, 13];

console.log(arr.every(isBelowThreshold));  // true

or

[12, 5, 8, 130, 44].every(x => x >= 10); // false
[12, 54, 18, 130, 44].every(x => x >= 10); // true

Palindrome

function palindrome(str) {
	return str.split('').every((char, index) => {
		const rdx = str.length - index - 1;
		return char === str.substr(rdx, 1);
	});
}
palindrome('aba');	// true

Using Array.some()

The some() method tests whether at least one element in the array passes the test implemented by the provided function. It returns a Boolean value.

const arr = [1, 2, 3, 4, 5];

var even = function(element) {
  // checks whether an element is even
  return element % 2 === 0;
};

console.log(arr.some(even));

or

[2, 5, 8, 1, 4].some(x => x > 10);  // false
[12, 5, 8, 1, 4].some(x => x > 10);	// true


Set

Set is a keyed collection data structure ie a collection using keys, the elements are iterable in the order of insertion.

The Set object lets you store unique values of any type, whether primitive values or object references.

const set1 = new Set([1, 2, 3, 4, 5]);
console.log(set1.has(1));		// true
console.log(set1.has(5));		// true
console.log(set1.has(6));		// false
const text = 'abcda';
const mySet = new Set(text);
console.log(' size ', mySet.size); // 4
console.log('mySet ', mySet); // 'a', 'b', 'c', 'd'

Remove duplicates from an array

const numbers = [2, 3, 4, 2, 3, 4, 1];
console.log([...new Set(numbers)]);	// 2,3,4,1

Arrays

const myArray = ['value1', 'value2', 'value3'];
const mySet = new Set(myArray);
console.log(mySet.has('value1')); // true

const array = [...mySet];
console.log(array); // [ 'value1', 'value2', 'value3' ]

Objects

const obj = { a: 1, b: 2, c: 3 };
const mySet = new Set();
mySet.add(1);
mySet.add(obj);
console.log('mySet ', mySet); // Set { 1, { a: 1, b: 2, c: 3 } }

for (const item of mySet) {
	console.log(item);	// 1, { a: 1, b: 2, c: 3 }
}


Babel Transpiler

cd /Users/jv/Desktop/MyDevelopment/github/javascript/the-complete-javascript-course/babel

npm init

npm install —save-dev babel-cli babel-preset-es2015 babel-polyfill

./node_modules/.bin/babel —presets es2015 script.js —out-file script-transpiled.js

copy node_modules/babel-polyfill/dist/polyfill.min.js

change index.html to add refs