Master Modern JavaScript skills with this amazing guide
Tags: javascript, react, angular, vue
Published: 2020-12-03 04:47:52

![Mastering Modern JavaScript](https://modernjavascript.yogeshchavan.dev/book_cover.jpg)

### Introduction

I've been working on a new book called [Mastering Modern JavaScript](https://modernjavascript.yogeshchavan.dev/) and it's finally released.

In today's constantly changing world, a lot of new content and updates are coming to JavaScript which are very useful for improving your code quality. 

Knowing these things are really important whether it's for getting a high paying job or to keep up to date with the latest trends and improve your code quality or to sustain your current Job.

There are a lot of tutorials/articles on the internet that explains those things. But it's very difficult to find that information when required and the information which is easy to digest.

So instead of constantly searching for something to revise that topic, I decided to create a book where you can find all the required information at once place.

There are many latest additions to JavaScript like **Nullish coalescing operator**, **optional chaining**, **Promises**, **async/await**, **ES6 destructuring**, and a lot more other features which are very useful.

So this book covers all of the latest JavaScript features added in ES6 and above along with the most frequently used Array methods and frequently asked coding question with its solution and explanation.

**It's the only guide you need to master Modern JavaScript skills.**

**This book contains a total of 144 pages of specialized content that is easy to digest and understand.**

The **Mastering Modern JavaScript** book includes

* Everything you need to learn about Modern JavaScript
* JavaScript Knowledge needed to get a high paying job
* Coding question with solution and explanation
* Essential things to become better at libraries and frameworks like React, Angular, Vue etc

## Table Of Contents

![Table Of Contents](https://modernjavascript.yogeshchavan.dev/contents.png)

**You can explore everything about this book at [this website](https://modernjavascript.yogeshchavan.dev/).**

Let's explore some of the things covered in this book.

## Let and const

Before ES6 came, JavaScript was using `var` keyword so JavaScript was only having a function and global scope. There was no block-level scope.

With the addition of `let` and `const` JavaScript has added block scoping.

**using let:**

When we declare a variable using `let` keyword, we **can assign** a new value to that variable later but we **cannot re-declare** it with the same name.

```js
// ES5 Code
var value = 10;
console.log(value); // 10

var value = "hello";
console.log(value); // hello

var value = 30;
console.log(value); // 30
```

As can be seen above, we have re-declared the variable `value` using `var` keyword multiple times.

Before ES6, we were able to re-declare a variable that is already declared before which was not having any meaningful use, instead, it was causing confusion.

If we already have a variable declared with the same name somewhere else and we're re-declaring it without knowing we already have that variable then we might override the variable value causing some difficult to debug issues.

So when using `let` keyword, you will get an error when you try to re-declare the variable with the same name which is a good thing.

```js
// ES6 Code
let value = 10;
console.log(value); // 10

let value = "hello"; // Uncaught SyntaxError: Identifier 'value' has already been declared
```

But, the following code is valid

```js
// ES6 Code
let value = 10;
console.log(value); // 10

value = "hello";
console.log(value); // hello
```

We don't get an error in the above code because we're **re-assigning** a new value to the `value` variable but we're **not re-declaring** `value` again.

Now, take a look at the below code:

```js
// ES5 Code
var isValid = true;
if(isValid) {
  var number = 10;
  console.log('inside:', number); // inside: 10
}
console.log('outside:', number); // outside: 10
```

As you can see in the above code when we declare a variable with `var` keyword, it's available outside the `if` block also.

```js
// ES6 Code
let isValid = true;
if(isValid) {
  let number = 10;
  console.log('inside:', number); // inside: 10
}

console.log('outside:', number); // Uncaught ReferenceError: number is not defined
```

As you can see in the above code, the `number` variable when declared using `let` keyword is only accessible inside the if block and outside the block it's not available so we got a reference error when we tried to access it outside the if block.

But if there was a `number` variable outside the if block, then it will work as shown below:

```js
// ES6 Code
let isValid = true;
let number = 20;

if(isValid) {
  let number = 10;
  console.log('inside:', number); // inside: 10
}

console.log('outside:', number); // outside: 20
```

Here, we have two `number` variables in a separate scope. So outside the if block, the value of `number` will be 20.

Take a look at the below code:

```js
// ES5 Code
for(var i = 0; i < 10; i++){
 console.log(i);
}
console.log('outside:', i); // 10
```

When using the `var` keyword, `i` was available even outside the `for` loop.

```js
// ES6 Code
for(let i = 0; i < 10; i++){
 console.log(i);
}

console.log('outside:', i); // Uncaught ReferenceError: i is not defined
```

But when using `let` keyword, it's not available outside the loop.

So as can be seen from the above code samples, using `let` keyword makes the variable available only inside that block and it's not accessible outside the block.

We can also create a block by a pair of curly brackets like this:

```js
let i = 10;
{
 let i = 20;
 console.log('inside:', i); // inside: 20
 i = 30;
 console.log('i again:', i); // i again: 30
}

console.log('outside:', i); // outside: 10
```

If you remember, I said we cannot re-declare a `let` based variable in the same block but we can re-declare it in another block. As can be seen in the above code, we have re-declared `i` and assigned a new value of `20` inside the block and once declared, that variable value will be available only in that block.

Outside the block when we printed that variable, we got `10` instead of the previously assigned value of `30` because outside the block, the inside `i` variable does not exist.

If we don't have the variable `i` declared outside, then we'll get an error as can be seen in the below code:

```js
{
 let i = 20;
 console.log('inside:', i); // inside: 20
 i = 30;
 console.log('i again:', i); // i again: 30
}

console.log('outside:', i); // Uncaught ReferenceError: i is not defined
```

**using const:**

`const` keyword works exactly the same as the `let` keyword in block scoping functionality. So let's look at how they differ from each other.

When we declare a variable as `const`, it's considered a constant variable whose value will never change.

In the case of `let` we're able to assign a new value to that variable later like this:

```js
let number = 10;
number = 20;

console.log(number); // 20
```

But we can't do that in case of `const`

```js
const number = 10;
number = 20; // Uncaught TypeError: Assignment to constant variable.
```

We even **can't re-declare** a `const` variable.

```js
const number = 20;
console.log(number); // 20

const number = 10; // Uncaught SyntaxError: Identifier 'number' has already been declared
```

Now, take a look at the below code:

```js
const arr = [1, 2, 3, 4];

arr.push(5);

console.log(arr); // [1, 2, 3, 4, 5]
```

We said `const` variable is constant whose value will never change but we have changed the constant array above. So isn't it contrary?

> No. Arrays are reference types and not primitive types in JavaScript

So what actually gets stored in `arr` is not the actual array but only the reference(address) of the memory location where the actual array is stored.

So by doing `arr.push(5);` we're not actually changing the reference where the `arr` points to but we're changing the values stored at that reference.

The same is the case with objects:

```js
const obj = {
 name: 'David',
 age: 30
};

obj.age = 40;

console.log(obj); // { name: 'David', age: 40 }
```

Here, also we're not changing the reference of where the `obj` points to but we're changing the values stored at that reference.
So the above code will work but the below code will not work.

```js
const obj = { name: 'David', age: 30 };
const obj1 = { name: 'Mike', age: 40 };
obj = obj1; // Uncaught TypeError: Assignment to constant variable.
```

The above code does not work because we're trying to change the reference that the `const` variable points to.

> So the key point to remember when using `const` is that, when we declare a variable as a constant using `const` we cannot re-define and we cannot re-assign that variable but we can change the values stored at that location if the variable is of reference type.

So the below code is invalid because we're re-assigning a new value to it.

```js
const arr = [1, 2, 3, 4];
arr = [10, 20, 30]; // Uncaught TypeError: Assignment to constant variable.
```

But note that, we can change the values inside the array, as seen previously.

The following code of re-defining a `const` variable is also invalid.

```js
const name = "David";
const name = "Raj"; // Uncaught SyntaxError: Identifier 'name' has already been declared
```

## Conclusion
* The keywords `let` and `const` adds block scoping in JavaScript.
* When we declare a variable as `let`, we cannot `re-define` or `re-declare` another let variable with the same name in the same scope(function or block scope) but we can `re-assign` a value to it.
* When we declare a variable as `const`, we cannot `re-define` or `re-declare` another `const` variable with the same name in the same scope(function or block scope) but we can change the values stored in that variable if the variable is of a reference type like array or object.

-----

## ES6 Import And Export Syntax

Before ES6 came into play, we were having multiple `script` tags in a single HTML file to import different javascript files like this:

```
<script type="text/javascript" src="home.js"></script>
<script type="text/javascript" src="profile.js"></script>
<script type="text/javascript" src="user.js"></script>
```

So, if we have a variable with the same name in different javascript files, it will create a naming conflict and the value you are expecting will not be the actual value you get.

ES6 has fixed this issue with the concept of modules.

Every javascript file we write in ES6 is known as a module and the variables and functions we declare in each file are not available to other files until we specifically export them from that file and import it into another file.

So the functions and variables defined in the file are private to each file and can’t be accessed outside the file until we export them.

There are two types of exports:

* Named Export: There can be multiple named exports in a single file
* Default Exports: There can be only one default export in a single file

### Named Exports

To export a single value as a named export, we export it like this:

```js
export const temp = "This is some dummy text";
```

If we have multiple things to export, we can write an export statement on a separate line instead of in front of variable declaration and specify the things to export in curly brackets.

```js
const temp1 = "This is some dummy text1";
const temp2 = "This is some dummy text2";
export { temp1, temp2 };
```

Note that, the export syntax is not an object literal syntax. So in ES6, to export something, we can't use key-value pairs like this:

```js
 // This is invalid syntax of export in ES6
export { key1: value1, key2: value2 }
```

To import the things we exported as named export, we use the following syntax:

```js
import { temp1, temp2 } from './filename';
```

Note, while importing something from the file, we don't need to add the `.js` extension to the filename as it's considered by default.

```js
// import from functions.js file from current directory 
import { temp1, temp2 } from './functions';

// import from functions.js file from parent of current directory
import { temp1 } from '../functions';
```

Codesandbox Demo: https://codesandbox.io/s/hardcore-pond-q4cjx

**One thing to note is that the name used while exporting has to match with the name we use while importing.**

So if you are exporting as:

```js
// constants.js
export const PI = 3.14159;
```

then while importing we have to use the same name used while exporting

```js
import { PI } from './constants';
```

we can't use any other name like this:

```js
import { PiValue } from './constants'; // This will throw an error
```

But if we already have the variable with the same name as the exported variable, we can use the renaming syntax while importing like this:

```js
import { PI as PIValue } from './constants';
```

Here we have renamed `PI` to `PIValue` and so we can’t use the `PI` variable name now, we have to use `PIValue` variable to get the exported value of `PI`.

We can also use the renaming syntax at the time of exporting:

```js
// constants.js
const PI = 3.14159; 

export { PI as PIValue };
```

then while importing we have to use `PIValue` like this:

```js
import { PIValue } from './constants';
```

To export something as named export, we have to declare it first.

```js
export 'hello'; // this will result in error
export const greeting = 'hello'; // this will work
export { name: 'David' }; // This will result in error
export const object = { name: 'David' }; // This will work
```

**The order in which we import the multiple named exports is not important.**

Take a look at the below `validations.js` file.

```js
// utils/validations.js

const isValidEmail = function(email) {
if (/^[^@ ]+@[^@ ]+\.[^@ \.]{2,}$/.test(email)) {
    return "email is valid";
  } else {
    return "email is invalid";
  }
};

const isValidPhone = function(phone) {
if (/^[\\(]\d{3}[\\)]\s\d{3}-\d{4}$/.test(phone)) {
    return "phone number is valid";
  } else {
    return "phone number is invalid";
  }
};

function isEmpty(value) { if (/^\s*$/.test(value)) {
    return "string is empty or contains only spaces";
  } else {
    return "string is not empty and does not contain
spaces";
  } 
}

export { isValidEmail, isValidPhone, isEmpty };
```

and in `index.js` we use these functions as shown below:

```js
// index.js
import { isEmpty, isValidEmail } from "./utils/validations";

console.log("isEmpty:", isEmpty("abcd")); // isEmpty: string is not empty and does not contain spaces

console.log("isValidEmail:", isValidEmail("abc@11gmail.com")); // isValidEmail: email is valid

console.log("isValidEmail:", isValidEmail("ab@c@11gmail.com")); // isValidEmail: email is invalid
```

Codesandbox Demo: https://codesandbox.io/s/youthful-flower-xesus

As you can see, we can import only the required exported things and in any order, so we don’t need to check in what order we exported in another file. That’s the beauty of named exports.

### Default Exports

As said earlier, there can be at most one default export in a single file.

You can, however, combine multiple named exports and one default export in a single file.

To declare a default export we add the default keyword in front of the export keyword like this:

```js
//constants.js
const name = 'David'; 
export default name;
```

To import the default export we don’t add the curly brackets as we were doing in named export like this:

```js
import name from './constants';
```

If we have multiple named exports and one default export like this:

```js
// constants.js
export const PI = 3.14159; 
export const AGE = 30;
const NAME = "David";
export default NAME;
```

then to import all on a single line we need to use the default exported variable before the curly bracket only.

```js
// NAME is default export and PI and AGE are named exports here
import NAME, { PI, AGE } from './constants';
```

**One specialty of default export is that we can change the name of the exported variable while importing:**

```js
// constants.js
const AGE = 30;
export default AGE;
```

And in another file, we can use another name while importing

```js
import myAge from ‘./constants’; 

console.log(myAge); // 30
```

Here, we have changed the name of the default exported variable from `AGE` to `myAge`.

This works because there can be only one default export so you can name it whatever you want.

**Another thing to note about default export is that the export default keyword cannot come before variable declaration like this:**

```js
// constants.js
export default const AGE = 30; // This is an error and will not work
```

so we have to use the export default keyword on a separate line like this:

```js
// constants.js 

const AGE = 30; 
export default AGE;
```

We can, however, export default without declaring the variable like this:

```js
//constants.js
export default {
 name: "Billy",
 age: 40
};
```

and in another file use it like this:

```js
import user from './constants';
console.log(user.name); // Billy 
console.log(user.age); // 40
```

There is another way of importing all the variables exported in a file using the following syntax:

```js
import * as constants from './constants';
```

Here we are importing all the named and default exports we have in `constants.js` and stored in `constants` variable. So, `constants` will become an object now.

```js
// constants.js
export const USERNAME = "David";
export default {
 name: "Billy",
 age: 40
};
```

and in another file, we use it as below:

```js
// test.js
import * as constants from './constants';
console.log(constants.USERNAME); // David
console.log(constants.default); // { name: "Billy", age: 40 }
console.log(constants.default.age); // 40
```

Codesandbox Demo: https://codesandbox.io/s/green-hill-dj43b

If you don’t want to export on separate lines for default and named
exports, you can combine it as shown below:

```js
// constants.js
const PI = 3.14159; const AGE = 30;
const USERNAME = "David";
const USER = {
 name: "Billy",
 age: 40 
};

export { PI, AGE, USERNAME, USER as default };
```

Here we are exporting `USER` as default export and others as named exports.

In another file, you can use it like this:

```js
import USER, { PI, AGE, USERNAME } from "./constants";
```

Codesandbox Demo: https://codesandbox.io/s/eloquent-northcutt-7btp1

## Conclusion

1. In ES6, data declared in one file is not accessible to another file until it is exported from that file and imported into another file.
2. If we have a single thing in a file to export like class declaration, we use default export otherwise we use named export. We can also combine default and named exports in a single file.

-----

## Default Parameters

ES6 has added a pretty useful feature of providing default parameters while defining functions.

Suppose, we have an application, where once the user login into the system, we show them a welcome message like this:

```js
function showMessage(firstName) {
  return "Welcome back, " + firstName;
}
console.log(showMessage('John')); // Welcome back, John
```

But what if we don’t have the user name in our database as it was an optional field while registering. Then we can show the `Welcome Guest` message to the user after login.

So we first need to check, if the `firstName` is provided and then display the corresponding message. Before ES6, we have to write code like this:

```js
function showMessage(firstName) {
  if(firstName) {
    return "Welcome back, " + firstName;
  } else {
    return "Welcome back, Guest";
  }
}

console.log(showMessage('John')); // Welcome back, John 
console.log(showMessage()); // Welcome back, Guest
```

But now in ES6 using default function parameters we can write the above code as shown below:

```js
function showMessage(firstName = 'Guest') {
   return "Welcome back, " + firstName;
}

console.log(showMessage('John')); // Welcome back, John 
console.log(showMessage()); // Welcome back, Guest
```

**We can assign any value as a default value to the function parameter.**

```js
function display(a = 10, b = 20, c = b) { 
 console.log(a, b, c);
}

display(); // 10 20 20
display(40); // 40 20 20
display(1, 70); // 1 70 70
display(1, 30, 70); // 1 30 70
```

As you can see, we have assigned unique values to a and b function parameters but for c we're assigning the value of b. So whatever value we have provided for b will be assigned to c also if there is no specific value provided for c while calling the function.

In the above code, we have not provided all the arguments to the function. So the above function calls will be the same as below:

```js
display(); // is same as display(undefined, undefined, undefined)
display(40); // is same as display(40, undefined, undefined)
display(1, 70); // is same as display(1, 70, undefined)
```

So if the argument passed is `undefined`, the default value will be used for the corresponding parameter.

**We can also assign complex or calculated value as a default value.**

```js
const defaultUser = {
  name: 'Jane',
  location: 'NY',
  job: 'Software Developer'
};

const display = (user = defaultUser, age = 60 / 2 ) => { 
 console.log(user, age);
};
display();

/* output

{
  name: 'Jane',
  location: 'NY',
  job: 'Software Developer'
} 30 

*/
```

Now, take a look at the below ES5 code:

```js
// ES5 Code
function getUsers(page, results, gender, nationality) {
  var params = "";
  if(page === 0 || page) {
   params += `page=${page}&`; 
  }
  if(results) {
   params += `results=${results}&`;
  }
  if(gender) {
   params += `gender=${gender}&`;
  }
  if(nationality) {
   params += `nationality=${nationality}`;
  }

  fetch('https://randomuser.me/api/?' + params) 
   .then(function(response) {
     return response.json(); 
   })
   .then(function(result) { 
    console.log(result);
   }) 
   .catch(function(error) {
     console.log('error', error); 
   }); 
}

getUsers(0, 10, 'male', 'us');
```

In this code, we’re making an API call to the [Random user](https://randomuser.me/) API by passing various optional parameters in the `getUsers` function.

So before making the API call, we have added various if conditions to check if the parameter is added or not, and based on that we’re constructing the query string like this: `https://randomuser.me/api/? page=0&results=10&gender=male&nationality=us`

But instead of adding so many if conditions, we can use the default parameters while defining the function parameters as shown below:

```js
function getUsers(page = 0, results = 10, gender = 'male',nationality = 'us') {
 fetch(`https://randomuser.me/api/?page=${page}&results=${results}&gender=${gender}&nationality=${nationality}`)
 .then(function(response) { 
  return response.json();
 }) 
 .then(function(result) {
   console.log(result); 
 })
 .catch(function(error) { 
  console.log('error', error);
  }); 
}

getUsers();
```

As you can see, we have simplified the code a lot. So when we don’t provide any argument to the `getUsers` function, it will take default values and we can also provide our own values like this:

```js
getUsers(1, 20, 'female', 'gb');
```

So it will override the default parameters of the function.

### null is not equal to undefined

But you need to be aware of one thing is that `null` and `undefined` are two different things while defining default parameters.

Take a look at the below code:

```js
function display(name = 'David', age = 35, location = 'NY'){
 console.log(name, age, location); 
}

display('David', 35); // David 35 NY
display('David', 35, undefined); // David 35 NY
```

As we have not provided the third parameter in the first call to display, it will be `undefined` by default so the default value of location will be used in both of the function calls. But the below function calls are not equal.

```js
display('David', 35, undefined); // David 35 NY
display('David', 35, null); // David 35 null
```

When we pass `null` as an argument, we’re specifically telling to assign `null` value to `location` parameter which is not the same as `undefined`, so it will not take the default value of `NY`.

## Closing points

Want to learn all ES6+ features in detail including let and const, promises, various promise methods, array and object destructuring, arrow functions, async/await, import and export and a whole lot more?

Check out my [Mastering Modern JavaScript](https://yogeshchavan1.podia.com/mastering-modern-javascript?coupon=LA1HR55) book. This book covers all the pre-requisites for learning React and helps you to become better at JavaScript and React.

Also, check out my free [Introduction to React Router](https://yogeshchavan1.podia.com/react-router-introduction) course to learn React Router from scratch.

Want to stay up to date with regular content regarding JavaScript, React, Node.js? [Follow me on LinkedIn](https://www.linkedin.com/in/yogesh-chavan97/).

[<img src="https://cdn.buymeacoffee.com/buttons/default-yellow.png" >](https://www.buymeacoffee.com/myogeshchavan97)