Why should you learn Modern JavaScript — ES6
Some ES6 features
JavaScript ES6 brings new syntax and new awesome features to make your code more modern and more readable. It allows you to write less code and do more. ES6 introduces us to many great features.
1. Default Parameters in ES6
Default function parameters allow named parameters to be initialized with default values if no value or undefined
is passed.
function multiply(x, y= 1) {
return x* y;
}console.log(multiply(9, 2));
// expected output: 18console.log(multiply(9));
// expected output: 9
2. Template Literals in ES6
Template Strings use back-ticks (``
) rather than the single or double quotes we're used to with regular strings. A template string could thus be written as follows:
var greeting = `Hello World!`;
So far, Template Strings haven’t given us anything more than normal strings do. Let’s change that.
String Substitution
One of their first real benefits is string substitution. Substitution allows us to take any valid JavaScript expression (including saying, the addition of variables) and inside a Template Literal, the result will be output as part of the same string.
Template Strings can contain placeholders for string substitution using the ${ }
syntax, as demonstrated below:
// Simple string substitution
var name = "Brendan";
console.log(`Yo, ${name}!`);// => "Yo, Brendan!"
As all string substitutions in Template Strings are JavaScript expressions, we can substitute a lot more than variable names. For example, below we can use expression interpolation to embed for some readable inline math:
var a = 10;
var b = 10;
console.log(`JavaScript first appeared ${a+b} years ago. Wow!`);//=> JavaScript first appeared 20 years ago. Wow!console.log(`The number of JS MVC frameworks is ${2 * (a + b)} and not ${10 * (a + b)}.`);
//=> The number of JS frameworks is 40 and not 200.
They are also very useful for functions inside expressions:
function fn() { return "I am a result. Rarr"; }
console.log(`foo ${fn()} bar`);
//=> foo I am a result. Rarr bar.
The ${}
works fine with any kind of expression, including member expressions and method calls:
var user = {name: 'Caitlin Potter'};
console.log(`Thanks for getting this into V8, ${user.name.toUpperCase()}.`);// => "Thanks for getting this into V8, CAITLIN POTTER";// And another example
var thing = 'template strings';
console.log(`Say hello to ${thing}.`);// => Say hello to template strings
If you require backticks inside of your string, it can be escaped using the backslash character \
as follows:
var greeting = `\`Yo\` World!`;
3. Multi-line Strings in ES6
Multiline strings in JavaScript have required hacky workarounds for some time. Current solutions for them require that strings either exist on a single line or be split into multiline strings using a \
(backslash) before each new line. For example:
var greeting = "Yo \
World";
Whilst this should work fine in most modern JavaScript engines, the behavior itself is still a bit of a hack. One can also use string concatenation to fake multiline support, but this equally leaves something to be desired:
var greeting = "Yo " +
"World";
Template Strings significantly simplify multiline strings. Simply include newlines where they are needed and BOOM. Here’s an example:
Any whitespace inside of the backtick syntax will also be considered part of the string.
console.log(`string text line 1
string text line 2`);
4. Destructuring Assignment in ES6
The two most used data structures in JavaScript are Object
and Array
.
- Objects allow us to create a single entity that stores data items by key.
- Arrays allow us to gather data items into an ordered list.
Although, when we pass those to a function, it may need not an object/array as a whole. It may need individual pieces.
Destructuring assignment is a special syntax that allows us to “unpack” arrays or objects into a bunch of variables, as sometimes that’s more convenient.
Destructuring also works great with complex functions that have a lot of parameters, default values, and so on. Soon we’ll see that.
Array destructuring
Here’s an example of how an array is destructured into variables:
// we have an array with the name and surname
let arr = ["John", "Smith"]// destructuring assignment
// sets firstName = arr[0]
// and surname = arr[1]
let [firstName, surname] = arr;alert(firstName); // John
alert(surname); // Smith
Now we can work with variables instead of array members.
It looks great when combined with split
or other array-returning methods:
let [firstName, surname] = "John Smith".split(' ');
alert(firstName); // John
alert(surname); // Smith
As you can see, the syntax is simple. There are several peculiar details though. Let’s see more examples, to better understand it.
5. Enhanced Object Literals in ES6
The ability to create JavaScript objects using literal notation is powerful. New features introduced from ES2015 (ES6) make object handling even easier in all modern browsers (not IE) and Node.js.
Creating objects in some languages can be expensive in terms of development time and processing power when a class
must be declared before anything can be achieved. In JavaScript, it’s easy to create objects on the fly. For example:
// ES5-compatible code
var myObject = {
prop1: 'hello',
prop2: 'world',
output: function() {
console.log(this.prop1 + ' ' + this.prop2);
}
};myObject.output(); // hello world
Single-use objects are used extensively. Examples include configuration settings, module definitions, method parameters, return values from functions, etc. ES2015 (ES6) added a range of features to enhance object literals.
6. Arrow Functions in ES6
Arrow functions were introduced in ES6.
Arrow functions allow us to write shorter function syntax:
With Arrow Function:
hello = () => {
return “Hello World!”;
}
It gets shorter! If the function has only one statement, and the statement returns a value, you can remove the brackets and the return
keyword:
Arrow Functions Return Value by Default:
hello = () => “Hello World!”;
Note: This works only if the function has only one statement.
If you have parameters, you pass them inside the parentheses:
Arrow Function With Parameters:
hello = (val) => “Hello “ + val;
In fact, if you have only one parameter, you can skip the parentheses as well:
Arrow Function Without Parentheses:
hello = val => “Hello “ + val;
7. Promises in ES6
A Promise
is a proxy for a value not necessarily known when the promise is created. It allows you to associate handlers with an asynchronous action's eventual success value or failure reason. This lets asynchronous methods return values like synchronous methods: instead of immediately returning the final value, the asynchronous method returns a promise to supply the value at some point in the future.
A Promise
is in one of these states:
- pending: initial state, neither fulfilled nor rejected.
- fulfilled: meaning that the operation was completed successfully.
- rejected: meaning that the operation failed.
A pending promise can either be fulfilled with a value or rejected with a reason (error). When either of these options happens, the associated handlers queued up by a promise’s then
method are called. If the promise has already been fulfilled or rejected when a corresponding handler is attached, the handler will be called, so there is no race condition between an asynchronous operation completing and its handlers being attached.
8. Block-Scoped Constructs Let and Const
Let
let
is now preferred for variable declaration. It's no surprise as it comes as an improvement to var
declarations. It also solves the problem var
that we just covered. Let's consider why this is so.
let is block scoped
A block is a chunk of code bounded by {}. A block lives in curly braces. Anything within curly braces is a block.
So a variable declared in a block let
is only available for use within that block. Let me explain this with an example:
let greeting = "say Hi";
let times = 4; if (times > 3) {
let hello = "say Hello instead";
console.log(hello);// "say Hello instead"
}
console.log(hello) // hello is not defined
We see that using hello
outside its block (the curly braces where it was defined) returns an error. This is because let
variables are block-scoped.
let can be updated but not re-declared.
Just like, a variable declared with let
can be updated within its scope. Unlike, a let
variable cannot be re-declared within its scope. So while this will work:
let greeting = "say Hi";
greeting = "say Hello instead";
this will return an error:
let greeting = "say Hi";
let greeting = "say Hello instead"; // error: Identifier 'greeting' has already been declared
However, if the same variable is defined in different scopes, there will be no error:
let greeting = "say Hi";
if (true) {
let greeting = "say Hello instead";
console.log(greeting); // "say Hello instead"
}
console.log(greeting); // "say Hi"
Why is there no error? This is because both instances are treated as different variables since they have different scopes.
This fact makes let
a better choice than var
. When using let
, you don't have to bother if you have used a name for a variable before as a variable exists only within its scope.
Also, since a variable cannot be declared more than once within scope, then the problem discussed earlier that occurs with var
does not happen.
Hoisting of let
Just like var
, let
declarations are hoisted to the top. Unlike var
which is initialized as undefined
, the let
keyword is not initialized. So if you try to use a let
variable before the declaration, you'll get a Reference Error
.
Const
Variables are declared with the const
maintain constant values. const
declarations share some similarities with let
declarations.
const declarations are block-scoped
Like let
declarations, const
declarations can only be accessed within the block they were declared.
const cannot be updated or re-declared
This means that the value of a variable declared with const
remains the same within its scope. It cannot be updated or re-declared. So if we declare a variable with const
, we can neither do this:
const greeting = "say Hi";
greeting = "say Hello instead";// error: Assignment to constant variable.
nor this:
const greeting = "say Hi";
const greeting = "say Hello instead";// error: Identifier 'greeting' has already been declared
Every const
declaration, therefore, must be initialized at the time of declaration.
This behavior is somehow different when it comes to objects declared with const
. While a const
object cannot be updated, the properties of this objects can be updated. Therefore, if we declare a const
object as this:
const greeting = {
message: "say Hi",
times: 4
}
while we cannot do this:
greeting = {
words: "Hello",
number: "five"
} // error: Assignment to constant variable.
we can do this:
greeting.message = "say Hello instead";
This will update the value of greeting.message
without returning errors.
Hoisting of const
Just like let
, const
declarations are hoisted to the top but are not initialized.
So just in case you missed the differences, here they are:
var
declarations are globally scoped or function scoped whilelet
andconst
are block scoped.var
variables can be updated and re-declared within its scope;let
variables can be updated but not re-declared;const
variables can neither be updated nor re-declared.- They are all hoisted to the top of their scope. But while
var
variables are initialized withundefined
,let
andconst
variables are not initialized. - While
var
andlet
can be declared without being initialized,const
must be initialized during declaration.
9. Classes in ES6
ECMAScript 2015, also known as ES6, introduced JavaScript Classes.
JavaScript Classes are templates for JavaScript Objects.
JavaScript Class Syntax
Use the keyword class
to create a class.
Always add a method named constructor()
:
Syntax
class ClassName {
constructor() { … }
}
Example
class Car {
constructor(name, year) {
this.name = name;
this.year = year;
}
}
The example above creates a class named “Car”.
The class has two initial properties: “name” and “year”.
A JavaScript class is not an object.
It is a template for JavaScript objects.
Using a Class
When you have a class, you can use the class to create objects:
Example
let myCar1 = new Car(“Ford”, 2014);
let myCar2 = new Car(“Audi”, 2019);
The example above uses the Car class to create two Car objects.
The constructor method is called automatically when a new object is created.
The Constructor Method
The constructor method is special:
- It has to have the exact name “constructor”
- It is executed automatically when a new object is created
- It is used to initialize object properties
If you do not define a constructor method, JavaScript will add an empty constructor method.
Class Methods
Class methods are created with the same syntax as object methods.
Use the keyword class
to create a class.
Always add a constructor()
method.
Then add any number of methods.
Syntax
class ClassName {
constructor() { … }
method_1() { … }
method_2() { … }
method_3() { … }
}
Create a Class method named “age”, that returns the Car age:
Example
class Car {
constructor(name, year) {
this.name = name;
this.year = year;
}
age() {
let date = new Date();
return date.getFullYear() — this.year;
}
}let myCar = new Car(“Ford”, 2014);
document.getElementById(“demo”).innerHTML =
“My car is “ + myCar.age() + “ years old.”;
You can send parameters to Class methods:
Example
class Car {
constructor(name, year) {
this.name = name;
this.year = year;
}
age(x) {
return x — this.year;
}
}let date = new Date();
let year = date.getFullYear();let myCar = new Car(“Ford”, 2014);
document.getElementById(“demo”).innerHTML=
“My car is “ + myCar.age(year) + “ years old.”;
10. Modules in ES6
Modules in ES6 is an essential concept. Although it is not available everywhere, we can use it and transpile into ES5 code. Transpilation is the process of converting the code from one language into its equivalent language. The ES6 module transpiler tool is responsible for taking the ES6 module and converts it into a compatible code of ES5 in the AMD (Asynchronous module definition is a specification for the JavaScript programming language) or in the CommonJS style.
We can use Gulp, Babel, Grunt, or other transpilers for compiling the modules during the build process. The variables and functions in a module are not available for use unless the file exports them.