Most of the freshers become confused about landing on ES6 from ES5. Even when I started learning the features of ES6, I thought that es5 was better. After some days, it came to my percipience that how es6 made js developers' life easier. So let’s play with es6 and gain some immense pleasure.
Block Bindings, Hoisting (let vs const vs var)
At first, we have to face the two new words let and const. You may have heard to give up var and start using let and const. Why? what’s the problem with var? You have already introduced with function scope and block scope. Simply block scope is nothing but wrapping everything under curly braces. Var and let, const perform under function scope and block scope respectively. What does it mean? see the example below:
function foo() {
var a = 1;
let b = 2;console.log(a); //1
console.log(b); //2{
var c = 3;
let d = 4;
}console.log(c); //3
console.log(d); //ReferenceError: d is not defined
}
foo();
we have a function called foo() in which we have declared two variables with var and let(you can also use const here), then we have wrapped another variable called c declared with let within curly braces. So the magical event occurs within curly braces. We are able to access c outside of the block but not d. Because let is block-scoped and var is function-scoped. The same thing happens with const. Now the question is what’s wrong with var?
function foo() {
console.log(a); //undefined
console.log(b); //ReferenceError: Cannot access 'b' before initializationvar a = 1;
let b = 2;
}foo();
So here is the problem you may have noticed before. Here we have two types of error. One is undefined and the other is a reference error. Firstly talk about undefined. We have declared and initialized a but here shows undefined. Why is this happening? let’s write the same but this time without var:
function foo() {
console.log(a); //ReferenceError: a is not defineda = 1; //initialized but not declaredconsole.log(a); //1
}foo();
This time a is not defined, as expected. Because we have initialized, but not declared(declaration means calling a variable without a value with memory allocation, initialization means assigning a value to that variable. This is strict definition, we can simply say initialization automatically occurs at the time of declaration by the JS engine). Hope that makes sense. Now the case of undefined is for hoisting. It is the default behavior of JS that moves the variable declaration to the top of the code. Now variables get hoisted, var gets undefined initialized to its value by default, let and const also get hoisted, but they are not set to undefined by default because they are block-scoped. There is a related to them is the temporal dead zone(TDZ). TDZ starts from where the scope gets started and ends with the declaration of the variable.
//TDZ
//TDZ
//TDZ
let b = 2; //declaration and initialization
console.log(b) //2
Now if you want to access b before declaration I mean initialization, it will throw the most common error we have seen before because of the TDZ. This is the restriction of ES6 as well.
Now let’s have a look at the other difference between let, const, and var I have skipped. We have already discussed one of the most important differences. The rest are we can assign as many value as we can to var and let but not const. Otherwise you will get TypeError: Assignment to constant variable:
function foo() {
var a = 1;a = 2;console.log(a); //2
}foo();
function bar() {
let a = 1;a = 2;console.log(a); //2
}bar();function baz() {
const a = 1;a = 2;console.log(a); //TypeError: Assignment to constant variable.
}baz();
Last but not least, it will be an unfinished story if we don't talk about Block Bindings in Loops:
function foo() {
var i = 10;for (var i = 0; i < 5; i++) {
console.log(i);
}console.log("output:", i); //output: 5
}foo();
function bar() {
let i = 10;for (let i = 0; i < 5; i++) {
console.log(i);
}console.log("output:", i); //output: 10
}bar();
Here is the same case of block scoping of let.
Regular function vs Fat Arrow function:
This is another interesting hot topic of ES6. I will not talk much more rather directly see the differences:
- Syntax: The first notable difference is their syntax. let’s see:
function foo() {
console.log("Hello! I am regular function");
}foo();-------const bar = () => {
console.log("Hello! I am arrow function");
}bar();
2. Duplicate Parameter: Duplicate parameter is not allowed in arrow function even in non-strict mode:
function sum(x, x) {
var add = x + x;console.log(add); //8
}sum(2, 4);-----"use strict";
function sum(x, x) {
var add = x + x;console.log(add); //SyntaxError: Duplicate parameter name not allowed in this context
}sum(2, 4);-----const sum = (x, x) => {
const add = x + x;console.log(add); //SyntaxError: Duplicate parameter name not allowed in this context
};sum(2, 4);
3. Arrow function is not constructible: You are not allowed to use new keyword as arrow function can’t be used as constructors.
function foo(a, b) {
var add = a + b;console.log(add);
}new foo(1, 2);-----const bar = (a, b) => {
const add = a + b;console.log(add);
};new bar(1, 2); //TypeError: bar is not a constructor
Magic of three dots(Spread Operator vs Rest Parameter)
So there are other useful things ES6 has gifted us. Spread operator and rest parameter. But there is a little bit of confusion between these. And that is three dots(…). So let me make this diaphanous.
Spread operator is something whose main duty is to spread. For example, we can consider two arrays arr1 and arr2. Spread operator takes the value of arr1 and spreads its value across arr2 and returns a new array:
const arr1 = [1, 2, 3, 4, 5];const arr2 = [6, 7, 8, 9, 10];const newArr = [...arr1, ...arr2];console.log(newArr); //[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]-----const arr = [1, 3, 5, 7];const foo = (a, b, c, d) => {
console.log(a + b + c + d);
};foo(...arr);
Hmm, the spread operator is so powerful. As you can see it directly accepts a whole array and adds the elements. Now let’s see what the rest parameters can do.
Basically, rest parameter wraps everything into an array passed as arguments.
function foo(...args) {
console.log(args); // ["John Doe", 103, "Web Developer"]
}foo("John Doe", 103, "Web Developer");
So the main difference we have to notice is spread operator breaks down an array and spreads all the elements into another array(copy one array into another) On the other hand rest parameter takes an uncertain number of elements into an array.