JavaScript - ES2015 (aka ES6)
The ES2015
Since this long time passed between ES5.1 and ES6, the release is full of important new features and major changes in suggested best practices in developing JavaScript programs. To understand how fundamental ES2015 is, just keep in mind that with this version, the specification document went from 250 pages to ~600.
In this blog, we describe the most important changes.
- Arrow Functions
- A new
this
scope - Promises
- Generators
let
andconst
- Classes
- Constructor
- Super
- Getters and setters
- Modules
- Importing modules
- Exporting modules
- Template Literals
- Default parameters
- The spread operator
- Destructuring assignments
- Enhanced Object Literals
- Simpler syntax to include variables
- Prototype
- super()
- Dynamic properties
- For-of loop
- Map and Set
- New String methods
- New Object methods
Arrow functions since their introduction changed how most JavaScript code looks (and works).
Visually, it’s a simple and welcome change, from:
const something = function something() {
//...
}
to
const something = () => {
//...
}
And if the function body is a one-liner, just:
const something = () => doSomething()
Also, if you have a single parameter, you could write:
const something = param => doSomething(param)
This is not a breaking change, regular
function
s will continue to work just as before.A new this scope
The
this
scope with arrow functions is inherited from the context.
With regular
function
s this
always refers to the nearest function, while with arrow functions this problem is removed, and you won’t need to write var that = this
ever again.Promises
Promises allow us to eliminate the famous “callback hell”, although they introduce a bit more complexity (which has been solved in ES2017 with
async
, a higher level construct).
Promises have been used by JavaScript developers well before ES2015, with many different libraries implementations (e.g. jQuery, q, deferred.js, vow etc), and the standard put a common ground across differences.
By using promises you can rewrite this code
setTimeout(function() {
console.log('I promised to run after 1s')
setTimeout(function() {
console.log('I promised to run after 2s')
}, 1000)
}, 1000)
as
const waitForPromise = () => new Promise((resolve, reject) => {
setTimeout(resolve, 1000)
})
waitForPromise().then(() => {
console.log('I promised to run after 1s')
return wait()
})
.then(() => console.log('I promised to run after 2s'))
Generators
Generators are a special kind of function with the ability to pause itself, and resume later, allowing other code to run in the meantime.
All this is done with a single, simple keyword:
yield
. When a generator contains that keyword, the execution is halted.
A generator can contain many
yield
keywords, thus halting itself multiple times, and it’s identified by the *function
keyword, which is not to be confused with the pointer dereference operator used in lower level programming languages such as C, C++ or Go.
Generators enable whole new paradigms of programming in JavaScript, allowing:
- 2-way communication while a generator is running
- long-lived while loops which do not freeze your program
Here is an example of a generator which explains how it all works.
function *calculator(input) {
var doubleThat = 2 * (yield (input / 2))
var another = yield (doubleThat)
return (input * doubleThat * another)
}
We initialize it with
const calc = calculator(10)
Then we start the iterator on our generator:
calc.next()
This first iteration starts the iterator. The code returns this object:
{
done: false
value: 5
}
What happens is: the code runs the function, with
input = 10
as it was passed in the generator constructor. It runs until it reaches the yield
, and returns the content of yield
: input / 2 = 5
. So we got a value of 5, and the indication that the iteration is not done (the function is just paused).
In the second iteration we pass the value
7
:calc.next(7)
and what we got back is:
{
done: false
value: 14
}
7
was placed as the value of doubleThat
. Important: you might read like input / 2
was the argument, but that’s just the return value of the first iteration. We now skip that, and use the new input value, 7
, and multiply it by 2.
We then reach the second yield, and that returns
doubleThat
, so the returned value is 14
.
In the next, and last, iteration, we pass in 100
calc.next(100)
and in return we got
{
done: true
value: 14000
}
As the iteration is done (no more yield keywords found) and we just return
(input * doubleThat * another)
which amounts to 10 * 14 * 100
.
let
and const
var
is traditionally function scoped.let
is a new variable declaration which is block scoped.
This means that declaring
let
variables in a for loop, inside an if or in a plain block is not going to let that variable “escape” the block, while var
s are hoisted up to the function definition.const
is just like let
, but immutable.
In JavaScript moving forward, you’ll see little to no
var
declarations any more, just let
and const
.const
in particular, maybe surprisingly, is very widely used nowadays with immutability being very popular.Classes
Traditionally JavaScript is the only mainstream language with prototype-based inheritance. Programmers switching to JavaScript from class-based language found it puzzling, but ES2015 introduced classes, which are just syntactic sugar over the inner working, but changed a lot how we build JavaScript programs.
Now inheritance is very easy and resembles other object-oriented programming languages:
class Person {
constructor(name) {
this.name = name
}
hello() {
return 'Hello, I am ' + this.name + '.'
}
}
class Actor extends Person {
hello() {
return super.hello() + ' I am an actor.'
}
}
var tomCruise = new Actor('Tom Cruise')
tomCruise.hello()
(the above program prints “Hello, I am Tom Cruise. I am an actor.”)
Classes do not have explicit class variable declarations, but you must initialize any variable in the constructor.
Constructor
Classes have a special method called
constructor
which is called when a class is initialized via new
.Super
The parent class can be referenced using
super()
.Getters and setters
A getter for a property can be declared as
class Person {
get fullName() {
return `${this.firstName} ${this.lastName}`
}
}
Setters are written in the same way:
class Person {
set age(years) {
this.theAge = years
}
}
Modules
Before ES2015, there were at least 3 major modules competing standards, which fragmented the community:
- AMD
- RequireJS
- CommonJS
ES2015 standardized these into a common format.
Importing modules
Importing is done via the
import ... from ...
construct:import * from 'mymodule'
import React from 'react'
import { React, Component } from 'react'
import React as MyLibrary from 'react'
Exporting modules
You can write modules and export anything to other modules using the
export
keyword:export var number = 2
export function bar() { /* ... */ }
Template Literals
Template literals are a new syntax to create strings:
const aString = `A string`
They provide a way to embed expressions into strings, effectively inserting the values, by using the
${a_variable}
syntax:const joe = 'test'
const string = `something ${joe}` //something test
You can perform more complex expressions as well:
const string = `something ${1 + 2 + 3}`
const string2 = `something ${doSomething() ? 'x' : 'y' }`
and strings can span over multiple lines:
const string3 = `Hey
this
string
is awesome!`
Compare how we used to do multiline strings pre-ES2015:
var str = 'One\n' +
'Two\n' +
'Three'
Default parameters
Functions now support default parameters:
const someFunction = function(index = 0, testing = true) { /* ... */ }
someFunction()
The spread operator
You can expand an array, an object or a string using the spread operator
...
.
Let’s start with an array example. Given
const a = [1, 2, 3]
you can create a new array using
const b = [...a, 4, 5, 6]
You can also create a copy of an array using
const c = [...a]
This works for objects as well. Clone an object with:
const newObj = { ...oldObj }
Using strings, the spread operator creates an array with each char in the string:
const hey = 'hey'
const arrayChar = [...hey] // ['h', 'e', 'y']
This operator has some pretty useful applications. The most important one is the ability to use an array as function argument in a very simple way:
const f = (arg1, arg2) => {}
const a = [1, 2]
f(...a)
(in the past you could do this using
f.apply(null, a)
but that’s not as nice and readable)Destructuring assignments
Given an object, you can extract just some values and put them into named variables:
const person = {
firstName: 'Tom',
lastName: 'Cruise',
actor: true,
age: 54, //made up
}
const {firstName: name, age} = person
name
and age
contain the desired values.
The syntax also works on arrays:
const a = [1,2,3,4,5]
const [first, second] = a
This statement creates 3 new variables by getting the items with index 0, 1, 4 from the array
a
:const [first, second, , , fifth] = a
Enhanced Object Literals
In ES2015 Object Literals gained superpowers.
Simpler syntax to include variables
Instead of doing
const something = 'y'
const x = {
something: something
}
you can do
const something = 'y'
const x = {
something
}
Prototype
A prototype can be specified with
const anObject = { y: 'y' }
const x = {
__proto__: anObject
}
super()
const anObject = { y: 'y', test: () => 'zoo' }
const x = {
__proto__: anObject,
test() {
return super.test() + 'x'
}
}
x.test() //zoox
Dynamic properties
const x = {
['a' + '_' + 'b']: 'z'
}
x.a_b //z
For-of loop
ES5 back in 2009 introduced
forEach()
loops. While nice, they offered no way to break, like for
loops always did.
ES2015 introduced the
for-of
loop, which combines the conciseness of forEach
with the ability to break://iterate over the value
for (const v of ['a', 'b', 'c']) {
console.log(v);
}
//get the index as well, using `entries()`
for (const [i, v] of ['a', 'b', 'c'].entries()) {
console.log(i, v);
}
Map and Set
Map and Set (and their respective garbage collected WeakMap and WeakSet) are the official implementations of two very popular data structures.
New String methods
Any string value got some new instance methods:
repeat()
repeats the strings for the specificed number of times:'Ho'.repeat(3) //HoHoHo
codePointAt()
handles retrieving the Unicode code of characters that cannot be represented by a single 16-bit UTF-16 unit, but need 2 instead
New Object methods
ES6 introduced several static methods under the Object namespace:
Object.is()
determines if two values are the same valueObject.assign()
used to shallow copy an objectObject.setPrototypeOf
sets an object prototype
This post is very simple to read and appreciate without leaving any details out. Great work!
ReplyDelete360DigiTMG pmp certification in malaysia
ReplyDeleteSimply the manner in which I have anticipated. Your site truly is intriguing.
training provider in malaysia
I think I have never watched such online diaries ever that has absolute things with all nuances which I need. So thoughtfully update this ever for us.
ReplyDeletehrdf scheme
Thank you for excellent article.You made an article that is interesting.
ReplyDeletedata science course gurgaon
Top 50 Casino Games | Casino Bonuses | Player Discussion
ReplyDeleteTop 50 Casino Games 일본야구 분석 사이트 · 1. Wild golden star West Gold · 2. 프로미넌스 포커 Sweet Bonanza · 3. Golden Dragon · 4. Wild you bet West 샌즈 Slots · 5. Wild West Roulette · 6.