Features I Wish I’d Known About ES6 & ES7
Many people consider JavaScript as the heart of dynamic web applications. and since it was created in 1997 by Brendan Eich. Over years especially after the EcmaScript standard JavaScript had severe and powerful changes including adding new features and fixing bugs or enhancing undesired behavior. In this article we will explore the new features added to JavaScript ES6 and ES7.
Historical Background
Oh wait a minute! What is ES6 and Who is responsible for developing and improving Javascript ?
Ecma and EcmaScript
As we mentioned earlier Javascript was originally created to live in the browser and make users life easier providing better user experience. After that Microsoft created its flavor of JavaScript to be used in their browser Internet Explorer.Thus, We needed a way to standardize the javaScript language and here Ecma International comes.
Ecma international is a standards organization that is responsible for making JavaScript specification and this specification is "EcmaScript". And in practice , the term “ javaScript” and “EcmaScript” are used interchangeably.
So What’s new ?
Now , let’s explore some of the most important and commonly used ES6 and ES7 features.
- Let and Const
- Arrow Functions
- Default parameters
- Destruction assignment
- Class keyword
- Generators
- Promises
- Array.prototype.includes (ES7)
- Exponential operator (ES7)
Scopes and variables declaration (let & const)
Scope is where our variables live and are accessible in. Before ES6 JavaScript had only two types of scopes.
- Global scope " when we declare variables outside functions."
- Function scope
var x = 1; // global Scope
function myFunction() {
var x = 2;
console.log("Inside function x is ", x); // Function Scope
}
myFunction(); // Result : Inside function x is 2
console.log("In global scope x is ", x); // Result : In global scope x is 1
In the previous example when we invoke the function (myFunction) we get x = 2 while in global x = 1 . because we have two different values of x depending on the scope of the variable.
Now, let's try another example:
var index = 5
for (var index = 0; index < 10; index++) {
// Do some tasks
}
console.log(index); // Result : 10
This seems odd as we would expect index = 5 as we see in the previous example but instead we got 10 ! \
As we mentioned earlier that we have only two types of scopes. So when we declare something like counter in for loop it is still in the global scope and that’s why we had this unexpected result.
Let and const keywords
EcmaScript2015 or ES6 introduced new keywords let
and const
to declare variables and fix var
problems. As these new keywords are block-scoped (a block is anything between { } ).
Let’s try the previous example using let
let index = 5;
for (let index = 0; index < 10; index++) {
// Do some tasks
}
console.log(index); // Result : 5
Now we got index = 5 as expected as let inside the for loop ( blocked between { }) has nothing to do with let in the global scope.
Another useful keyword is const
as it allows us to declare constant values (not meant to be changed).
const
is also block-scoped same as let
but the main difference between them is that const value can't be changed after assigning variable to a value.
const PI = 3.141592653589793;
PI = 3.14; // this line will cause a TypeError
Note
Re-assigning variables with const
keyword will cause error only if we assign a primitive value. But if we declare an object we can add new methods and properties to it. That is because when we declare a new object with const keyword we don’t store the whole object in the variable like primitive values instead we store a reference to this object. So it will cause an error only if we tried to change the reference to another object.
Now, let's see an example:
const obj1 = { name: "John Doe" };
obj1.age = 40; // this is totally fine and age property will be added to obj1
console.log(obj1.age); // result : 40
obj1 = { name: "Foo" }; // will cause a TypeError as we are changing the
Arrow Function
ES5 function statement:
const sumTwoNumbers = function (num1, num2) {
return num1 + num2;
}
ES6 provides new elegant and shorter syntax for function statements called Arrow function.
const sumTwoNumbers = (num1, num2) => { return num1 + num2; }
And this could be shorter though, If the function has only one statement and returns a value we can remove the return
keyword and the curly brackets. And this will give the same result as the previous example.
const sumTwoNumbers = (num1, num2) => num1 + num2;
In case we have only have one parameter we can remove the parentheses
const multiplyBy10 = num => num * 10;
Arrow Function and this
Arrow functions handle this
in a different way from regular functions. In regular functions this
keyword represented the object that called the function (the executer), which could be the window, the document, or whatever. While in the Arrow function this
represents the object that defined the arrow function.
In short , in arrow function this
represents the definition context while in regular function this
represents the execution context.
Now let’s take a look at a couple of examples two show the difference between each of them:
function myFunction() {
console.log(this);
}
const myArrowFunction = () => console.log(this);
myFunction(); // this = the Window object "The global object";
myArrowFunction(); // this = the Window object "The global object";
In this example both of the regular and arrow functions give the same thing and this
refers to the global object. In the case of a browser the global object is Window.
But there is a big difference between them although they gave the same result. In regular function this
is the Window object because the executor of the function is the global object aka Window. While in the Arrow function case this
is the Window because the arrow function was defined in the global scope.
Now let’s take another example to demonstrate this:
We have html file with javascript file imported in it and a simple button
<!DOCTYPE html>
<html lang="en">
.
.
.
<body>
<button id="btn">click</button>
<script src="./index.js"></script>
</body>
</html>
In index.js
function fn() {
console.log(this);
}
const btnElement = document.getElementById('btn');
btnElement.addEventListener('click', fn);
When clicking the button we will got this printed to the console and this will be:
<button id="btn">click</button>
Now let’s change fn function to an Arrow function and try again.
const fn = () => console.log(this);
const btnElement = document.getElementById('btn');
btnElement.addEventListener('click', fn);
When clicking the button we will get this printed to the console and this will be the Window object.
Explanation
In regular function this gets its meaning during runtime and refers to the object that executes it and this is the btnElement in our case.
In arrow function this gets its meaning from the definition context which is the global object and that’s why we get the Window object.
Default parameters
Another cool thing in the ES6 that default argument. If you are familiar with other programming languages you probably know what the default parameter is.
In short , it means that you can initialize a parameter with a default value if no value is passed when invoking the function. Let’s see an example to handle this before ES6.
// ES5 style for default parameters
function add(a, b) {
var b = (typeof b !== 'undefined') ? b : 5
return a + b
}
add(3, 4); // result = 7
add(1) // result = 6
In the previous example we introduced ES5 technique for handling default parameters. As we know javascript initializes parameters with “undefined” at first. So we check if parameter b is undefined this means that he had no value in the invoking line and then we assign a default value ( b = 5).
Now let’s see the new ES6 way for handling the same situation:
function add(a, b = 5) {
return a + b
}
add(3, 4); // result = 7
add(1) // result = 6
This is very simple and straightforward syntax.
Note
Keep in mind to keep all default parameters to the right otherwise you won’t get the proper result.
// Don't do this
function add(a = 4, b) {
return a + b
}
add(1) // result = NaN
// the right way
function add(a, b = 4) {
return a + b
}
add(1) // result = 5
Destruction assignment
Destruction is unpacking properties from objects or array elements into distinct separate variables. Lets first explore array destruction.
let colors = ['one', 'two', 'three']
let [red, blue, yellow] = colors
console.log(red); // one
console.log(blue); // two
console.log(yellow); // three
In the previous example we first declared an array (colors) and then using destruction we extracted elements from this array into separate variables. The first variable “red” will match the first element in the array and so on.
This is a very simple and elegant way to extract variables from an array into separate variables.
Swapping values
Let’s try this approach to swap variables:
let a = 5;
let b = 10;
[a, b] = [b, a]
console.log(a); // a = 10
console.log(b); // b = 5
Now, let’s see object destruction:
const user = {
id: 1,
name: "Ali",
age: "30"
}
// lets extract the user name only
const { name } = user
console.log(name); // Ali
Using destruction and default values
const user = {
id: 1,
name: "Ali",
}
const { name, age = 55 } = user
console.log(age); // 55
Object and array destruction is very handy and makes life easier especially when using it with extracting variables from an http request.
Class keyword
ES6 added class
keyword and unlike other traditional object-oriented supporting languages like java or c++ ,class keyword in Javascript is just a Syntactic sugar. And under the hood it’s just a special function. Let’s try it out.
class abc {
constructor(name, age) {
this.name = name;
this.age = age
}
}
// ES5 same output
var abc = function abc(name, age) {
this.name = name;
this.age = age;
};
Generators
In a regular function we return only one value when invoking the function (or nothing). But with this new ES6 features we will be able to return more than one value from a function. On at a time.to create a generator function we need a special syntax so Let’s see an example:
function* numberGenerator() {
yield 1;
yield 2;
return 3;
}
let generator = numberGenerator();
let one = generator.next();
let two = generator.next();
let last = generator.next();
console.log(one); // { value: 1, done: false }
console.log(two); // { value: 2, done: false }
console.log(last); // { value: 3, done: true }
Promises
JavaScript is a single-threaded language supporting synchronous and asynchronous operations. And promises are just a more elegant way to deal with these asynchronous tasks than callbacks. And a very handy way to avoid callback hell.
A promise is an object representing the result of asynchronous tasks which are tasks that don’t block the execution until it is finished. This approach is great for time consuming tasks.
Let’s see a simple example:
let promise = new Promise(function(resolve, reject) {
setTimeout(() => resolve("resolved!"), 1000);
});
// resolve runs the first function in .then
promise.then(
result => alert(result), // shows "done!" after 1 second
error => alert(error) // doesn't run
);
Array.prototype.includes
Although ES6 had many features and things to discuss but also ES7 introduced new features. Array.prototype.includes is a replacement for indexOf we use to check the presence of a value in an array.as indexOf had weird behavior as it returns a number and in case the element is not in the array it returns -1 .So we had to perform another check using the return number from indexOf. On the other hand includes is straightforward and returns boolean. Let’s see an example comparing these two alternatives.
let colors = ['red', 'white', 'black', 'blue']
// using indexOf
console.log(colors.indexOf('red')); // 0
console.log(colors.indexOf('purple')); // -1
if (colors.indexOf('purple') === -1) {
console.log("Not found");
}
// using includes
console.log(colors.includes('red')); // true
console.log(colors.includes('purple')); // false
if (!colors.includes('purple')) {
console.log("Not found");
}
Exponential operator
Let’s test one last ES7 feature for this article. In ES6 and earlier JS when it comes to exponential operators we had to work around to get the result as there wasn't an explicit operator. Let’s see how we would do this in ES6 syntax.
let result = Math.pow(2, 3)
console.log(result) // 8
We had to use the built-in method pow in Math object. Or we would make a function to get the same result. Now let’s see what it would be in ES7.
let a = 2 ** 3
let b = 3 ** 3
console.log(a === Math.pow(2, 3)) // true
console.log(b === Math.pow(3, 3)) // true
Very simple and easy to read as we see in other languages like python for instance.
Conclusion
JavaScript is becoming more popular over the years and it’s community is growing rapidly. We tried to cover some of the important features that ES6 and ES7 added to JS but there are more and more to learn.
Top comments (0)