JavaScript/ECMAScript 2015(ES6) is keep updating these days, So I will write about ES6 and main focus is to use React.js framework. I have summarized what I see as the major new features released in each ECMA Script version.
Versions of JavaScript
ES5 (2009)
- Standard Modules
import
andexport
- Standardized Promises
- Classes & Inheritance
- Block-scoped variables --
let
andconst
- Template Literals
- Object destructing into variables
- Generator functions
- Map and Set data structures
- Internationalization for Strings, Numbers and Dates via
Intl
API
ES6 / ES2015
Array.includes()
- Numeric exponent (power of) operator
**
ES8 / ES2017
async
functions- Object.entries
- String Padding functions
ES9 / ES2018
- Object Rest/Spread
const obj = { ...props };
- Asynchronous Iteration for
await (...) {
- Promise
finally()
function - Regular expression enhancements (lookbehind, named groups)
2015 - ECMAScript 2015 (ES6)
Some of the features of ES6:
- Variable Creation using
let
andconst
- Template Strings
- Arrow functions
- Rest and Spread Operator
- Destructuring
- Array functions
find()
andfindIndex()
- classes
- promises
Babel is a Preprocessor of JavaScript/ECMAScript. it is mainly used to convert ES6+ code into a backwards compatible version of JavaScript that can be run by older browsers.
Variable Creation using let
and const
let
is like a replacement of var
.
const
is used to create variables with constant values. The variables created using const
cannot be updated later in the code.
const PROJECT_URL = "https://github.com/jaykiran/100_DAYS_OF_CODE";
let num = 100;
let name = "jay";
let arr = [1, 2, 3];
let obj = {
title: "Readme",
description: "Modern JavaScript"
};
const num1 = 20;
Hoisting is not possible using let
num = 11;
console.log(num);
var num;
So, In the above case Hoisting is possible. But if we replace the var keyword with let, then the value of num will not be printed in the console.
Template Strings
Template string allows Embedding Expressions inside it. The Expressions are embedded by wrapping them inside ${}
.
For example:
let name = "jay";
//normal way
const greetings = "Hello" + " "+ name;
//using template string
const greetings = `Hello ${name}`;
console.log(greetings);
Arrow Functions
ES6 gives us a new syntax of defining functions using a fat arrow. Arrow functions bring a lot of clarity and code reduction.
function getFullName(firstName, lastName){
return(${firstName} ${lastName});
}
const greetings = (name) => {
return(`welcome ${name}`);
}
//when there is only one statement, we can write it as
const greetings = (name) => `welcome ${name}`;
Rest and Spread Operators
Rest Operator -
const sum = (num1, num2) => console.log(num1+num2);
sum(1,2,3,4,5);
// Output : 3
The arguments we are calling is greater than the arguments which are defined in the function.
By using Rest Operator, We can call any number of arguments.
const sum = (...args) => console.log(args);
sum(1,2,3,4,5);
//Output : [1,2,3,4,5]
The arguments we passed through function calling is passed as an array to the function. So, it gives the output as array elements.
const sum = (...args) =>{
let total=0
for(let i=0; i<args.length; i++){
total += args[i];
}
console.log(total);
}
sum(1,2,3,4,5);
// Output : 15
if we have something like this
const sum = (num1, num2, ...args) =>{
let total=0
for(let i=0; i<args.length; i++){
total += args[i];
}
console.log(total);
}
sum(1,2,3,4,5);
// Output : 12
..agrs should be at the end
eg: (num1, num2, ..args)
(..args, num1, num2)
will throw an error.
Spread Operator -
Spread Operator allows arrays and objects to be expanded into:
- Elements in the case of array.
- Key-Value pairs in the case of Objects.
it can be used for creating the reference elements.
let arr1 = [1,2,3,4,5];
let arr2= [...arr1];
arr1.push(6);
console.log(arr1);
console.log(arr2);
// Output: [1,2,3,4,5,6]
[1,2,3,4,5]
For Concatenation
let arr1 = [1,2,3,4,5];
let arr2= [6,7,8];
//normal way
let arr3 = arr1.concat(arr2);
//using spread Operator
let arr4 = [...arr1, ...arr2];
console.log(arr3);
console.log(arr4);
//Output: [1,2,3,4,5,6,7,8]
[1,2,3,4,5,6,7,8]
//sequence of array concatenation also matters here
let arr5 = [0, ...arr1, ...arr2, 9];
console.log(arr5);
//Output: [0,1,2,3,4,5,6,7,8,9]
In case of Objects -
let obj1 = {
name: "Jay" ,
lastName: "Guntuku"
}
let obj2 = {
age: 21
}
let obj3 = {...obj1, ...obj2}
console.log(obj3)
//Output: {name: "Jay", lastName: "Guntuku", age: 21}
Destructuring
It allows us to Unpack arrays or Objects into a bunch of variables which makes working with arrays and objects more convenient.
const name = "Jayakiran Guntuku";
const nameArr = name.split(' ');
console.log(nameArr);
//Output: ["Jayakiran", "Guntuku"]
//using Destructuring concept
let [firstName, lastName] = nameArr;
console.log(firstName);
console.log(lastName);
//Output: Jayakiran
Guntuku
In the case of Objects, we use this concept as follows -
let firstName= "Jayakiran",
let lastName= "Guntuku",
let age= 22
const person = {
firstName,
lastName,
age
}
console.log(person);
// Output: {firstName: "Jaykiran", lastName: "Guntuku", age: 22}
Array Functions: map()
map()
iterates the array for us and we can pass a callback
function to perform some operation in each array item. The updated values can be returned by the callback
function to create a new array.
Syntax: arr.map((item)=>{//callbackfunction})
const arr = [1,2,3,4,5];
let newArr = arr.map((item)=>{
//console.log(item);
return item*2;
});
console.log(arr);
console.log(newArr);
// Output: [1,2,3,4,5]
[2,4,6,8,10]
In the case of Objects, we use this concept as follows -
const arr = [
{
name: "John Doe",
experience: 2,
Role: "Software Developer"
},
{
name: "Elon Musk",
experience: 10,
Role: "Founder & CEO"
}
]
let newArr = arr.map((item, pos)=> {
console.log(data);
return {
name: data.name,
experience: data.experience
};
});
console.log(arr);
console.log(newArr);
Output:
{
name: "John Doe",
experience: 2,
Role: "Software Developer"
},
{
name: "Elon Musk",
experience: 10,
Role: "Founder & CEO"
},
0:
name: "John Doe",
experience: 2
1:
name: "Elon Musk",
experience: 10
Array Functions: reduce()
reduce()
also iterates the array for us and we can pass a callback
function to perform some operation in each array item. The difference is reduce()
passes the result of callback from one iteration to the next one. This callback
result is an Accumulator
. The Accumulator can be anything (integer, string, object or array) and must be instantiated and passed when calling reduce()
.
Syntax: arr.reduce((acc, item)=>{//callbackfunction},acc_default_value)
const arr = [1,2,3,4,5];
const result = arr.reduce((acc, item)=>{
return acc + item;
},0);
console.log(result);
//Output: 15
Array Functions: filter()
It iterates through the array to create a new array. We can decide which elements should be added in the new array based on some conditions.
Syntax: arr.filter(item =>{//Return true/false to add/skip the current item})
const arr = [1,2,3,4,5];
const resultArr = arr.filter(item =>{
return true; //Output: [1,2,3,4,5]
return false; //Output:
return item % 2 ==0 //Output: [2,4]
});
console.log(resultArr);
Array Functions: find() and findIndex()
find()
is used to search for element in the array that matches some condition. it returns the first element that matches the condition.
findIndex()
returns the index of the element.
const arr = [1,2,3,4,5];
const resultArr = arr.find(item =>{
return true; //Output: 1
return false; //Output: undefined
return item % 2 === 0 //Output: 2
});
console.log(resultArr);
const resultArr = arr.findIndex(item =>{
return item % 2 === 0 //Output: 1
});
console.log(resultArr);
Classes
Classes are a template for creating objects. They encapsulate data with code to work on that data.
class ClassName{
constructor(){
//initialize Properties here;
}
//Methods Outside constructor
method1 = () =>{
//Method Body
}
}
The body of a class is executed in strict mode, i.e., code written here is subject to stricter syntax for increased performance.
Strict mode makes several changes to normal JavaScript semantics:
- Eliminates some JavaScript silent errors by changing them to throw errors.
- Fixes mistakes that make it difficult for JavaScript engines to perform optimizations: strict mode code can sometimes be made to run faster than identical code that's not strict mode.
- Prohibits some syntax likely to be defined in future versions of ECMAScript
Example -
function person(name, birthYear){
this.name = name;
this.birthYear = birthYear;
this.getDetails = function(){
return "Name: " + this.name + "and age: " + (2020- this.birthYear);
}
}
var jay = new person('jay', 1998);
console.log(jay.getDetails);
//Output: Name: jay and age: 22
class person{
constructor(name, birthYear){
this.name = name;
this.birthYear = birthYear;
}
getDetails = function(){
return `Name: ${this.name} and age: ${2019-this.birthYear} `
}
}
var jay = new person('jay', 1998);
console.log(jay.getDetails);
//Output: Name: jay and age: 22
Inheritance
Inheritance is to create "child" object classes (constructors) that inherit features from their "parent" classes.
class ChildClass{
//body
}
class ChildClass extends ParentClass{
//body
}
Example -
class person{
constructor(name, birthYear){
this.name = name;
this.birthYear = birthYear;
}
getDetails = function(){
return `Name: ${this.name} and age: ${2019-this.birthYear} `
}
}
class Pilot extends Person{
constructor(name, birthYear, exp, type, license){
super(name, birthYear);
this.experience = exp;
this.type = type;
this.license = license;
}
getData = function(){
return `${this.getDetails} and Experience: ${this.experience} and type: ${this.type} `
}
}
var jay = new Pilot("Uday", 1999, 28, 'Private', 'XYZ123');
console.log(jay);
jay.getData;
Callbacks & Promises
A promise is used to handle the asynchronous result of an operation. JavaScript is designed to not wait for an asynchronous block of code to completely execute before other synchronous parts of the code can run. For instance, when making API requests to servers, we have no idea if these servers are offline or online, or how long it takes to process the server request.
With Promises, we can defer execution of a code block until an async
request is completed. This way, other operations can keep running without interruption.
Promises have Three States:
- Pending: This is the initial state of the Promise before an operation begins
- Fulfilled: This means the specified operation was completed
- Rejected: The operation did not complete; an error value is usually thrown
Creating a Promise
The Promise object is created using the new keyword and contains the promise
; this is an executor function which has a resolve and a reject callback. As the names imply, each of these callbacks returns a value with the reject callback returning an error object.
const myPromise = new Promise((resolve, reject) => {
//promise body
//call resolve() when the operation is complete
//call reject() when the operation is failed.
})
Using a Promise
Using a promise that has been created is straightforward; we use .then()
and .catch()
to our Promise like:
myPromise
.then(function(done) {
// the content from the resolve() is here
})
.catch(function(error) {
// the info from the reject() is here
});
Example -
// creating a promise
const weather = true
const date = new Promise(function(resolve, reject) {
if (weather) {
const dateDetails = {
name: 'Cubana Restaurant',
location: '55th Street',
table: 5
};
resolve(dateDetails)
} else {
reject(new Error('Bad weather, so no Date'))
}
});
//using promise
date
.then(function(done) {
// the content from the resolve() is here
})
.catch(function(error) {
// the info from the reject() is here
});
Async and Await
An async function is a modification to the syntax used in writing promises. An async
function returns a promise -- if the function returns a value, the promise will be resolved with the value, but if the async function throws an error, the promise is rejected with that value.
function foo() {
return Promise.reject(25)
}
// is equal to
async function() {
throw 25;
}
Await is only used with an async function. The await
keyword is used in anasync
function to ensure that all promises returned in the async
function are synchronized, ie. they wait for each other. Await eliminates the use of callbacks in .then()
and .catch()
. In using async
and await
, async
is prepended when returning a promise, await
is prepended when calling a promise. try
and catch
are also used to get the rejection value of an async
function.
async function f() {
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("done!"), 1000)
});
let result = await promise; // wait until the promise resolves
alert(result); // "done!"
}
f();
You can learn more about promises here.
Conclusion
Understanding the concepts of Callbacks, Promises, and async/await can be tricky sometimes, but till no we have seen how they will work when carrying out asynchronous operations and other ES6 features in JavaScript.
They techniques will come in handy a lot when making API requests and event handling.