DEV Community

Cover image for Top 6 ES6 Fundamentals You Need to Know
Chrysilla Mayasari
Chrysilla Mayasari

Posted on

Top 6 ES6 Fundamentals You Need to Know

Table Of Contents

What is ES6?

ES6 or ECMAScript 6 was the second major revision to Javascript, which enable us to write less and do more. It has a lot of new features and new syntaxes to make your code looks more modern, more structured and more readable.

On this article, we will cover several ES6 fundamentals that you need to master to get you ready with Modern Javascript. Let's dive in!

1. Let and Const

let: mutable variables, means we can reassign its value. let can be declared without being initialized.

const: immutable variables, means we cannot reassign value to const variables. const must be initialized during declaration.

Both of them are block-scope variables, which means it is only available within the block where the variable is declared.

Takeaways

It is recommended to use let and const than using var, because when we use let and const will be hoisted to the top but they are not initialized (unlike var that has been initialized with the value of undefined) and this helps us to get better error message. Furthermore, we can't iniatialized those variables before we declare them. This is useful to make sure that our variables has been declared before we can use them and this is a good practice in programming.

Code Examples:

// traditional
var x = 5;
y = 8;
var y;

console.log(x); // 5
console.log(y); // 8

// es6
let i = 10;
j = 15;
let j;
console.log(i); //10
console.log(j); // Error: Cannot access 'j' before initialization

const k = 29;
k = 39;
console.log(k); // Error: Assignment to constant variable.

let m;
m = 'hello';

const n;
n = 'goodbye';
console.log(m); // hello
console.log(n); // Error: Missing initializer in const declaration
Enter fullscreen mode Exit fullscreen mode

2. Arrow Functions

Let's begin by showing you how to write function in traditional syntax vs ES6 syntax.

// traditional
var sum = function (a, b) {
  return a + b;
}

// es6
const sum = (a, b) => a + b;
Enter fullscreen mode Exit fullscreen mode

It's really awesome, right?
The arrow function makes your code looks clean, more structured and more readable.

When the body inside arrow function has more than one line, we need to wrap it inside {}.

const sum = (a, b) => {
  const result = a + b;
  return result;
}
Enter fullscreen mode Exit fullscreen mode

Arrow function commonly used as callbacks. You will find it a lot when working with map(), filter() and reduce().

// traditional
const arr1 = [1,3,5];
const square1 = arr1.map(function(item) {
  return item ** 2;
});
console.log(square1); // [1, 9, 25]


// es6
const arr2 = [1,3,5];
const square2 = arr2.map(item => item ** 2);
console.log(square2);
Enter fullscreen mode Exit fullscreen mode

Although it is a powerful addition in ES6 but there are limitations that we need to understand to avoid errors that are difficult to track, such as when using this inside arrow function.

On the car2 example, the result might be something that you are not looking for. So, we need to be careful when using arrow function. This happens because arrow function doesn’t have its own bindings to this, instead they inherit from parent scope, which is called lexical scoping.

// with regular function
const car1 = {
  brand: 'Toyota',
  showBrand: function() {
    console.log(this.brand);
  }
}
car1.showBrand(); // 'Toyota'


// with arrow function
const car2 = {
  brand: 'Mazda',
  showBrand: () => console.log(this.brand)
}
car2.showBrand(); // undefined
Enter fullscreen mode Exit fullscreen mode

3. Template Literals

Template literals or template strings is a new way to concatenate strings in ES6.
Let's take a look at code example below.

This is how we create greetings function that will greet the given name in traditional syntax.

// traditional
var greetings = function (name) {
  return 'Hello ' +  name;
};
console.log(greetings('Bambang')); // 'hello Bambang'
Enter fullscreen mode Exit fullscreen mode

Now, let's refactor to template literals!

// es6
const greetings = (name) => `hello ${name}`;
console.log(greetings('Bambang')); // 'hello Bambang'
Enter fullscreen mode Exit fullscreen mode

With template literals, our code looks more structured. We don't need the + sign anymore and we can use ${} to call variables.

4. Default Parameters

In ES6, we can give default value to function's parameters.

With the old syntax, this is how we create default value to a parameter.

// traditional
var sayGoodbye = function (name) {
  name = name !== undefined ? name : Lorem Ipsum;
  return `Bye bye ${name}`
}
Enter fullscreen mode Exit fullscreen mode

Now, let's refactor using ES6 default parameter!

// es6
const sayGoodbye = (name = Lorem Ipsum ) => `Bye bye ${name}`
console.log(sayGoodbye()); // Bye bye Lorem Ipsum
console.log(sayGoodbye(Bambang)); // Bye bye Bambang
Enter fullscreen mode Exit fullscreen mode

It's so simple and easy to understand. This also helps you to handle error in advance when you forget to assign the parameter.

5. Rest Parameters and Spread Syntax

Previously, before we have rest parameter, we can code like this to convert arguments to array. However, it only supports limited number of arguments and you need to be sure how many items are there.

// traditional
var cities = function(city1, city2, city3, city4, city5) {
  var citiesToArray = Array.from(arguments);
  return citiesToArray;
}
console.log(cities('tokyo', 'singapore', 'jakarta', 'moscow', 'frankfurt')); // ['tokyo', 'singapore', 'jakarta', 'moscow', 'frankfurt']
Enter fullscreen mode Exit fullscreen mode

But now, thanks to ES6 which introduces us to Rest parameter.

Rest parameter accepts unlimited arguments and returns it as array. You can use rest parameter by adding three dots .... When you use rest paramater as argument inside a function, it must be at the end.

// es6
const cities = (city1, city2, ...others) => {
  console.log(city1); // 'tokyo'
  console.log(city2); // 'singapore'
  console.log(others); // ['jakarta', 'moscow', 'frankfurt']
}
cities('tokyo', 'singapore', 'jakarta', 'moscow', 'frankfurt');
Enter fullscreen mode Exit fullscreen mode

Because it turns our parameters into an array, we can combine it with map() just like the example below.

const doubleTheNumbers = (...args) => args.map(item => item * 2)
console.log(doubleTheNumbers(3,5,20)); // [6, 10, 40]
Enter fullscreen mode Exit fullscreen mode

Next we have spread syntax ..., which looks exactly the same as rest parameter.
However, spread syntax does quite the opposite of rest parameter. With spread syntax we can get list of arguments from array.

For example, let's say we have an array and we want to find the lowest number. Here's how we can do that with spread syntax.

const arr = [6, 5, 8, 2, 9];
console.log(Math.min(...arr)); // 2
Enter fullscreen mode Exit fullscreen mode

Besides that, we can easily push elements into array using spread syntax. Without spread syntax, it would be something like this, which might be not what we are looking for..

// traditional
const fruit1 = ['apple', 'mango'];
const fruit2 = ['strawberry', 'grape', 'melon'];
fruit1.push(fruit2)
console.log(fruit1); // ["apple", "mango", Array ["strawberry", "grape", "melon"]]
Enter fullscreen mode Exit fullscreen mode

Now, let's refactor with spread syntax!

// es6
const fruit1 = ['apple', 'mango'];
const fruit2 = ['strawberry', 'grape', 'melon'];
fruit1.push(...fruit2);
console.log(fruit1); // ["apple", "mango", "strawberry", "grape", "melon"]
Enter fullscreen mode Exit fullscreen mode

We can copy an array using spread syntax too!

// copy array
let nums = [3, 7, 5, 6];
let copyNums = [...nums];
copyNums.push(9);
console.log(nums); // [3, 7, 5, 6]
console.log(copyNums); // [3, 7, 5, 6, 9]
Enter fullscreen mode Exit fullscreen mode

Both rest parameter and spread syntax are really useful, powerful and easy to understand!

6. Destructuring Assignment

Destructuring assignment allows us to unpack values from array and properties from object into variables.

Array

This is how we destructure an array into variables.

const menu = ['chicken', 'beef'];
const [menu1, menu2] = menu;

console.log(menu1); // chicken
console.log(menu2); // beef
Enter fullscreen mode Exit fullscreen mode

We can also use destructuring assignment to swap between two values in array.

Here's how we swap array using traditional syntax.

// traditional
var swap = function() {
  var arr = [1,2];
  var temp;
  temp = arr[0];
  arr[0] = arr[1];
  arr[1] = temp;

  return arr;
}
console.log(swap()); // [2,1]
Enter fullscreen mode Exit fullscreen mode

And now, let's refactor the code using destructuring assignment!

//es6
let [a,b] = [1, 2];
[b,a] = [a,b];
console.log(a, b); // [2,1]
Enter fullscreen mode Exit fullscreen mode

We have less code and it's easier to understand, isn't it?

Object

We can also use destructuring assignment with object. Take a look at the example below.

Here's how we do it with traditional syntax to get the object's value.

// traditional
var car = {
  model: 'Toyota',
  year: 2015,
  colors: ['black', 'blue', 'yellow']
}

var model = car.model;
var year = car.year;
var colors = car.colors;

console.log(model);
console.log(year);
console.log(colors);
Enter fullscreen mode Exit fullscreen mode

Now let's refactor with destructuring assignment!

// es6
const car = {
  model: 'Toyota',
  year: 2015,
  colors: ['black', 'blue', 'yellow']
}

let {model, year, colors} = car;
console.log(model);
console.log(year);
console.log(colors);
Enter fullscreen mode Exit fullscreen mode

There's a lot more you can do with destructuring assignment as it is really useful and practical, especially when you are working with modern Javascript.

Bonus: Promise

In Javascript, Promise means doing something that takes time then produces a result, just like real-world promise.

After a Promise takes the time needed to produce the promised result, it will either resolve when it’s fulfilled or reject when there is an error. If it’s resolved, we can get access to the returned data and if it’s rejected, we can throw an error.

In this example, we want to create a network request from API that returns either a resolved Promise when it's succeed or a rejected Promise when we couldn't get the data.

const getTodo = (resource) => {
  return new Promise((resolve, reject) => {
    const request = new XMLHttpRequest();

    request.addEventListener("readystatechange", () => {
      if (request.readyState === 4 && request.status === 200) {
        const data = JSON.parse(request.responseText);
        resolve(data);
      } else if (request.readyState === 4) {
        reject("error getting resource");
      }
    });

    request.open("GET", resource);
    request.send();
  });
};

getTodo("https://jsonplaceholder.typicode.com/todos/1")
  .then(data => {
    console.log("promise resolved:", data);
  }).catch(err => {
    console.log("promise rejected:", err)
  });
Enter fullscreen mode Exit fullscreen mode

Promise is a part of Asynchronous Javascript, a technique that allows us to create an action that we start now and finish later, which means we can let our code do several things without blocking the main thread.

If you want to learn more on Asynchronous Javascript, you can head over to my Async/await post.


Thanks for reading!

Would really appreciate if you could share your thoughts and feedbacks in the comment ✨

Top comments (0)