ECMAScript 6 functionalities
In this topic, we will demonstrate how to use some of the new functionalities of ES6, which may be useful in the everyday JavaScript coding and which will also be useful to simplify the examples presented in the next chapters of this book. Among the functionalities, we will cover the following ones:
let
andconst
- Template literals
- Destructuring
- Spread operator
- Arrow functions using
=>
- Classes
Declaring variables with let instead of var
Until ES5, we could declare variables in any place of our code, even if we overwrote the variables declaration, as in the following code:
var framework = 'Angular'; var framework = 'React'; console.log(framework);
The output of the preceding code is React
as the last variable declared, named framework, was assigned this value. In the previous code, we had two variables with the same name; this is very dangerous and might drive the code to an incorrect output.
Other languages, such as C, Java, and C#, do no allow this behavior. With ES6, a new keyword was introduced, called let
. Let is the new var
keyword, meaning we can simply substitute the keyword var
for let
. In the following code, we have an example:
let language = 'JavaScript!'; //{1} let language = 'Ruby!'; // {2} - throws error console.log(language);
Line {2}
will throw an error because a variable named language is already declared in the same scope (line {1}
). We will discuss the let
and variables scope in the next topic.
Tip
The preceding code can be tested and executed at the URL https://goo.gl/he0udZ .
Variables scope with let
To understand how variables declared with let
keyword work, let's use the following example (you can run the example using the URL
https://goo.gl/NbsVvg
):
let movie = 'Lord of the Rings'; //{1} //var movie = 'Batman v Superman'; //throws error, variable movie already declared function starWarsFan(){ let movie = 'Star Wars'; //{2} return movie; } function marvelFan(){ movie = 'The Avengers'; //{3} return movie; } function blizzardFan(){ let isFan = true; let phrase = 'Warcraft'; //{4} console.log('Before if: ' + phrase); if (isFan){ let phrase = 'initial text'; //{5} phrase = 'For the Horde!'; //{6} console.log('Inside if: ' + phrase); } phrase = 'For the Alliance!'; //{7} console.log('After if: ' + phrase); } console.log(movie); //{8} console.log(starWarsFan()); //{9} console.log(marvelFan()); //{10} console.log(movie); //{11} blizzardFan(); //{12}
This will be the output from the previous code:
Lord of the Rings
Star Wars
The Avengers
The Avengers
Before if: Warcraft
Inside if: For the Horde!
After if: For the Alliance!
Now, we will discuss the reason we got this output.
- On line
{1}
, we declared a variablemovie
with the valueLord of the Rings
, and we output its value on line{8}
. This variable has global scope, as you learned in the Variable scope section of this chapter. - On line
{9}
, we executed thestarWarsFan
function. Inside this function, we also declared a variable namedmovie
on line{2}
. The output from this function isStar Wars
because the variable from line{2}
has local scope, meaning it is only valid inside this function.
- On line
{10}
, we executed themarvelFan
function. Inside this function, we changed the value of themovie
variable (line{3}
). This variable made a reference to the global variable declared on line{1}
. This is why we got the outputThe Avengers
on line{10}
and also on line{11}
, where we output the global variable. - Finally, we executed the
blizzardFan
function on line{12}
. Inside this function, we declared a variable namedphrase
(line{4}
) with the scope of the function. Then, on line{5}
, again, we will declare a variable namedphrase
, but this time, this variable will have only a scope inside theif
statement. - On line
{6}
, we changed the value ofphrase
. As we are still inside theif
statement, only the variable declared on line{5}
would have its value changed. - Then, on line
{7}
, we again changed the value ofphrase
, but as we are not inside the block of theif
statement, the value of the variable declared on line{4}
is changed.
Again, this scope behavior is the same as in other programming languages, such as Java or C. However, this was only introduced in JavaScript through ES6.
Constants
ES6 also introduced the keyword const
. Its behavior is the same thing as the keyword let
; the only difference is that a variable defined as const
has a read-only value, meaning a constant value.
For example, consider the following code:
const PI = 3.141593; PI = 3.0; //throws error console.log(PI);
When we try to assign a new value to PI
or even try to redeclare it as var PI
or let PI
, the code will throw an error saying that PI
is read only.
Tip
The preceding code can be executed at https://goo.gl/4xuWrC .
Template literals
Template literals are really nice because we can create strings without the need to concatenate the values.
For example, consider the following examples written with ES5:
var book = {
name: 'Learning JavaScript DataStructures and Algorithms'
};
console.log('You are reading ' + book.name + '.,\n and this is a new line\n and so is this.');
We can improve the syntax of the previous console.log
output with the following code:
console.log(`You are reading ${book.name}.,
and this is a new line
and so is this.`);
Template literals are enclosed by backticks (`
). To interpolate a variable value, we will simply set the variable value inside a dollar sign and curly braces (${}
), as we did with book.name
.
Template literals can also be used for multiline strings. There is no need to use \n
anymore. Simply hit
Enter
on the keyboard to take the string to a new line, as was done with and this is a new line
in the previous example.
This functionality will be very useful in our examples to simplify the output!
Tip
The preceding examples can be executed at https://goo.gl/PTqnwO .
Arrow functions
Arrow functions are a great way of simplifying the syntax of functions in ES6. Consider the following example:
var circleArea = function circleArea(r) { var PI = 3.14; var area = PI * r * r; return area; }; console.log(circleArea(2));
We can simplify the syntax of the preceding code to the following code:
let circleArea = (r) => { //{1} const PI = 3.14; let area = PI * r * r; return area; } console.log(circleArea(2));
The main difference is on line {1}
of the example, on which we can omit the keyword function using =>
.
If the function has a single statement, we can use a simpler version as well, by omitting the keyword return
. Take a look at the following:
let circleArea2 = (r) => 3.14 * r * r; console.log(circleArea2(2));
Tip
The preceding examples can be executed athttps://goo.gl/CigniJ .
Default parameter values for functions
With ES6, it is also possible to define default parameter values for functions. The following is an example:
function sum (x = 1, y = 2, z = 3) { return x + y + z }; console.log(sum(4,2)); //outputs 9
As we are not passing z
as a parameter, it will have value 3 by default. So, 4 + 2 + 3 == 9
.
Before ES6, we would have to write the preceding function as the following code:
function sum (x, y, z) { if (x === undefined) x = 1; if (y === undefined) y = 2; if (z === undefined) z = 3; return x + y + z; };
With ES6, we can save a few lines of code using the default parameter values functionality.
Tip
The preceding example can be executed at https://goo.gl/2MiJ59 .
Declaring the spread and rest operators
In ES5, we can turn arrays into parameters using the apply()
function. ES6 has the spread operator (...
) for this purpose. For example, consider the function sum we declared in the previous topic. We can execute the following code to pass the x
, y
, and z
parameters:
var params = [3, 4, 5]; console.log(sum(...params));
The preceding code is the same as the code written in ES5, as follows:
var params = [3, 4, 5]; console.log(sum.apply(undefined, params));
The spread operator (...
) can also be used as a rest parameter in functions to replace arguments
. Consider the following example:
function restParamaterFunction (x, y, ...a) { return (x + y) * a.length; } console.log(restParamaterFunction(1, 2, "hello", true, 7)); //outputs 9;
The preceding code is the same as the following:
function restParamaterFunction (x, y) { var a = Array.prototype.slice.call(arguments, 2); return (x + y) * a.length; };
Tip
The spread operator example can be executed at https://goo.gl/8equk5 , and the rest parameter example can be executed at https://goo.gl/LaJZqU .
Enhanced object properties
ES6 introduces a concept called array destructuring, which is a way of initializing variables at once. For example, consider the following:
var [x, y] = ['a', 'b'];
Executing the preceding code is the same as doing the following:
var x = 'a'; var y = 'b';
Array destructuring can also be performed to swap values at once without the need to create temp variables, as follows:
[x, y] = [y, x];
The preceding code is the same as the following one:
var temp = x; x = y; y = temp;
This will be very useful when you learn sorting algorithms as this swap values is very common.
There is also another functionality, called property shorthand, which is another way of performing the destructuring of objects. For example, consider the following example:
var [x, y] = ['a', 'b']; var obj = { x, y }; console.log(obj); // { x: "a", y: "b" }
The preceding code is the same as doing the following:
var x = 'a'; var y = 'b'; var obj2 = { x: x, y: y }; console.log(obj2); // { x: "a", y: "b" }
The last functionality we will discuss in this topic is called the method property. This allows developers to declare functions inside objects as if they were properties. The following is an example:
var hello = { name : 'abcdef', printHello(){ console.log('Hello'); } } console.log(hello.printHello());
The preceding code can also be written as follows:
var hello = { name: 'abcdef', printHello: function printHello() { console.log('Hello'); } };
The three examples presented can be executed at:
- Array destructuring: https://goo.gl/VsLecp
- Variable swap: https://goo.gl/EyFAII
- Property shorthand: https://goo.gl/DKU2PN
Object-oriented programming with classes
ES6 also introduced a cleaner way of declaring classes. You learned that we can declare a class named Book
in the Object oriented programming section this way:
function Book(title, pages, isbn){ //{1} this.title = title; this.pages = pages; this.isbn = isbn; } Book.prototype.printTitle = function(){ console.log(this.title); };
With ES6, we can simplify the syntax and use the following code:
class Book { //{2} constructor (title, pages, isbn) { this.title = title; this.pages = pages; this.isbn = isbn; } printIsbn(){ console.log(this.isbn); } }
We can simply use the keyword class
and declare a class with a constructor
function and other functions as well—for example, the printIsbn
function. The code for the class Book
declared on line {1}
has the same effect and output as the code declared on line {2}
:
let book = new Book('title', 'pag', 'isbn'); console.log(book.title); //outputs the book title book.title = 'new title'; //update the value of the book title console.log(book.title); //outputs the book title
Tip
The preceding example can be executed at https://goo.gl/UhK1n4 .
Inheritance
As we have a new way of declaring classes, there is also a simplified syntax to use inheritance between classes. Let's take a look at an example:
class ITBook extends Book { //{1} constructor (title, pages, isbn, technology) { super(title, pages, isbn); //{2} this.technology = technology; } printTechnology(){ console.log(this.technology); } } let jsBook = new ITBook('Learning JS Algorithms', '200', '1234567890', 'JavaScript'); console.log(jsBook.title); console.log(jsBook.printTechnology());
We can extend another class and inherit its behavior using the keyword extends
(line {1}
). Inside the constructor, we can also refer to the constructor
superclass using the keyword super
(line {2}
).
Although the syntax of this new way of declaring classes in JavaScript is very similar to other programming languages such as Java and C/C++, it is good to remember that JavaScript object-oriented programming is done through a prototype.
Tip
The preceding example can be executed at https://goo.gl/hgQvo9 .
Working with getters and setters
With the new class syntax, it is also possible to create getter and setter functions for the class attributes. Although class attributes are not private as in other object-oriented languages (the encapsulation concept), it is good to follow a naming pattern.
The following is an example of a class declaring a get
and set
function along with its use:
class Person { constructor (name) { this._name = name; //{1} } get name() { //{2} return this._name; } set name(value) { //{3} this._name = value; } } let lotrChar = new Person('Frodo'); console.log(lotrChar.name); //{4} lotrChar.name = 'Gandalf'; //{5} console.log(lotrChar.name); lotrChar._name = 'Sam'; //{6} console.log(lotrChar.name);
To declare a get
and set
function, we simply need to use the keyword get
or set
in front of the function name (lines {2}
and {3}
), which is the name we want to expose and to be used. We can declare the class attributes with the same name, or we can use underscore in front of the attribute name (line {1}
) to make it seem as though the attribute is private.
Then, to take a look at the get
or set
functions, we can simply refer to their names as it was a simple attribute (lines {4}
and {5}
).
Tip
It is also good to remember that the _name
attribute is not really private, and we can still make a reference to it. However, we will talk about this later on in this book.
This example can be executed at https://goo.gl/SMRYsv.
Other functionalities
ES6 also has some other functionalities; among them, we can list iterators, typed arrays, Set, Map, WeakSet, WeakMap, modules, tail calls, and Symbol. We will cover some of these other functionalities in other chapters of this book.
Note
For more information about all the functionalities of ES6 and its specification, refer to http://www.ecma-international.org/ecma-262/6.0/ .