11 JavaScript ES6 Features Every Developer Needs To Know

JavaScript runs the world.

It loaded the article you're currently reading, it's allowing you to scroll with your finger (or mouse) to see more content, and is also probably doing a million other things that we take for granted on a daily basis.

Developers who've mastered the inner workings of JavaScript will remind you that it wasn't always this way, though.

When JavaScript began, not only was it less powerful than it is now, but it was also less usable.

As programmers, we know that every technology we use should be powerful but what about user-friendly? If that technology makes creating programs difficult or unwieldy, it's probably time to switch tech stacks.

Luckily, JavaScript has gone through several iterations and upgrades, the most recent being ES6. With that update came a lot of much-needed features that make JavaScript (by far) the most functional tool in a web developer's arsenal.

1. Template Literals

Template literals are a convenient way of inserting variables within strings.

Here's the old way:

//The old way
let person = { firstName: "Ben", occupation: "Developer"};
let oldString = "Nice to meet you, " + person.firstName + "!"; 

Dealing with spacing and punctuation is a nightmare with this method, especially for long strings with lots of variables.

In ES6, we can do a bit better.

Use backticks to denote the start of a template string, and insert any variables you want using the ${ variableHere } syntax, like so:

//The new way
let person = { firstName: "Ben", occupation: "Developer"};
let templateString = `Nice to meet you, ${person.firstName}!`;

This is a really convenient tool that I use all the time when I'm constructing Strings, and should be a part of every JavaScript developer's toolkit.

2. Default Function Parameters

In ES6, we finally have the option to insert default function parameters.

In earlier versions of JavaScript, we had to use logic operators to check our inputs:

//The old way
let sum = function(a, b){ 
   a = a || 10; 
   b = b || 10; 
   // function logic goes here...

Now, instead of having to check each parameter, we can specify its value in the function definition:

//The new way
let sum = function(a = 10, b = 10){ 
    // function logic goes here... 

Not only is this less error-prone but it's also more readable.

Your colleagues and future-you will thank you for using default parameters, especially when code review rolls around.

3. The Spread Operator

This is a great little feature, and one of my favorite updates from ES6.

The spread operator, denoted as ... , allows us to extract the elements of an array and populate another array (or object).

Here are some examples of what you can do with the spread operator:

let arrayOne = [1, 2, 3];
let arrayTwo = [4, 5, 6]; 

//Make a shallow copy
let shallowCopy = [...arrayOne]; 

//Merge two arrays
let mergedArrays = [...arrayOne, ...arrayTwo]; 

While the spread operator is extremely versatile and a great tool to know, there's still a bit of lag in terms of browser support.

To recreate similar functionality while still maintaining backward compatibility, you can use Object.assign() for most use cases.

4. Object Destructuring

Object destructuring allows devlopers to extract only the necessary components of object or arrays to increase code performance and readability.

Let's look at a few examples:

//Object destructuring here: 
function printCatInfo({name, hobby}) {

 console.log(`${name} likes to ${hobby} all day.`);


let kitty = { 
    name: "Sir Scratchewan", 
    age: 20, 
    breed: "Domestic Long-hair", 
    hobby: "play with yarn"

//prints: "Sir Scratchewan likes to play with yarn all day."

In the function declaration, I wrapped the parameters in braces, specifying which properties we need in the function, i.e. {name, hobby} – the inputs need to match up perfectly for the function to correctly identify which properties it needs from the object.

Destructuring also helps you (and other code reviewers) understand functions more easily by hinting at which object properties are actually used.

5. Muli-Line Strings

Strings are cumbersome to work with, there's no denying that.

But, multi-line strings were especially bad before ES6.

Here's what they looked like:

//The old way
let multiline = 'multi-line string multi-line string,\n\t'
+ 'another line here\n\t'
+ 'another line here\n\t'
+ 'another line here\n\t'; 

In modern JS, we don't have to deal with all the new-line escaping because ES6 supports multi-line strings.

Just wrap your multi-line string with backticks, like so:

//The new way
let multiline = `this is a multi-line string!
                 Very easy to handle in ES6. 
                 Even with ${variable.name}!
                 Much pleased, very wow.`

Since we're already using backticks, you can also insert template literals, as we see in the third line of the multi-line string.

In general, I typically default to backtick-delimited strings for the flexibility (a string might become multi-line later in development, who knows).

6. Arrow Functions

Arrow functions are a complete game-changer in JavaScript, and something most frontend/full-stack developers use every day.

Let's look at code to understand them a bit more:

//The old way
function (param){   
    return param + 5; 

//The new way
(param) => {
   param + 5; 

//Even simpler: 
param => param + 5; // this is a completely valid ES6 function

Arrow functions are syntactic sugar for declaring and using functions, and allow us to condense functions into much cleaner code.

The => symbol is what separates our parameters from the return statement, and gives us the flexibility to omit function in our declarations.

7. Class Syntax

Classes have a been a bit controversial in JavaSCript, but anyone coming from Java or any other OOP-oriented language will welcome them with open arms.

In ES6, creating classes is really just syntactic sugar for prototypal inheritance, which the mechanism JavaScript uses to manage object relationships.

Here's how classes look in ES6:

class Cat(){ 
    constructor(name, breed) {
        this.name = name;
        this.breed = breed;

    toString() {
        return `${name} is a ${breed} type of cat.`;


class FluffyCat extends Cat(){ 
    static default() {
        return new FluffyCat('FlufferNutter', 'Ragdoll', 10);

    constructor(name, breed, fluffiness) {
        super(name, breed);
        this.fluffiness = fluffiness;


For Java enthusiasts, this syntax will look and feel familiar.

In practice, though, a lot of the features for classes in ES6 are overshadowed by functional programming.

8. Let & Const

Before ES6, the default variable declaration keyword was var and had a number of problems.

Most notably, variables declared with var had global scope which led to a lot of general frustration in the developer community.

ES6's introduced let and const as a response to this, and it's really cleared up variable declaration best practices.

Here's how they work:

let greeting = "hi!"
let counter = 5; 

if(counter > 3){ 
   let secondGreeting = "hey there!" 

// this will cause an error because let is block-scoped

When working with const, as the name implies, we're not able to change the value of the variable once it's set:

const num = 5; 
num = 7; //not allowed

//Const and arrays
const array = [1, 2, 3, 4];
array.pop(); // not allowed, it directly mutates the array

let newArray = [1, 2, 3];
array = newArray; // this is allowed, array now points to a new reference

The nuances of let and const are a bit tricky, but they offer a big improvement over var and will help you ensure your code is bug-free and much more consistent.

9. Modules

JavaScript was originally used to create small programs or scripts that would run in the browser and handle a few key tasks (rendering resources, animations, and so on).

As web development became more reliant on JavaScript and its related technologies, programs quickly grew in size and complexity. It became apparent pretty fast that there needed to be a mechanism to split those large programs into smaller chunks, and import only the necessary parts when needed.

This is the basic context behind modules, a features in ES6 that allows programmers to label a section of code (a module) and inject that functionality into other programs.

The basic functions of modules can be acheived with two keywords – import and export – let's start with export.

You can export pretty much anything in JavaScript, including the following:

  • Functions
  • Objects
  • Variables
  • Classes

Here's how it looks like in code:

/* 📁 File: example.js */ 

//Export array
export let days = ["Monday", "Tuesday", "Wednesday", Thursday", "Friday"]; 

//Export object
export let person = {name: "Ben", occupation: "Blogger"}; 

//Export class
export class Blogger() {
         this.name = name; 

We declared all of the above exports in example.js, so to use them in another file, we'd need to import each item:

/* 📁 File: main.js */ 

import {days, person, Blogger} from "./example.js"; 

let newBlogger = new Blogger("Rebecca"); // using imported object 

In the above code, we must declare the proper syntax of the modules from example.js or else they won't be imported properly. We can, however, choose to rename the variables or functions we're importing with the as keyword:

/* 📁 File: main.js */ 

import {Blogger as newClassLabel} from "./example.js"; 

let newBlogger = new newClassLabel("Rebecca"); // using imported object 

The as keyword makes it very easy to keep your import statements clean and concise, especially if the modules you're importing have confusing variable or function names.

10. Promises

Promises represent the outcome of an event that occurs asynchronously.

In ES6, the interface we can use, as developers, to handle asynchronous data through promises is cleaner and more streamlined.

Let's look at an example.

Say we're building a little social media website and we want users to upload profile pictures. Once they upload a picture, we save the image to our database, but only if it's below 5 MB.

Seems reasonable enough – but how do promises fit in?

Well, we would ideally display a message to the user after they upload a picture – either “Your image was successfully uploaded” or “This image was too large”. The key is that we need to wait for our database to finishing checking the image before we can can display any message.

This example underlines a key principle with Promises – they can either be successful or unsuccessful, and it's our job as the developer to handle both cases.

Here's what the first bit of code looks like:

// Set up Promise
let myPromise = new Promise((resolve, reject) => {

//specify when promise should resolve
if (uploadImageToDatabase(myImageObject)) {  
     resolve("Successfully uploaded");  
 else {

This is the basic set up for a Promise. It takes two arguments, the resolve and reject, which you can use to specify what happens when the Promises is successful or when it fails.

In the code snippet above, I invoke the method uploadImageToDatabase, which is the asynchronous method we're interested in. When it returns a result, if it's successful (a.k.a returns true) the promise will resolve, or else it will fail.

Now that the Promise is set up, we can decide what to do next when we find out the result – we can accomplish this with the then keyword:

//Handle Promise
myPromise.then((resolvedValue) => {
    //invoke method to display the correct message
    displayMessageToUser(resolvedValue); // "Successfully Uploaded" 
}, (error) => {
    displayMessageToUser(error);  //"Unsuccessful"

Remember, in our Promise declaration above we set the resolve function to return “Image Successfully Uploaded” . When we use then later on, we can access that value and then display it to the user as a message.

11. Array Helper Functions

Array helper functions are functions bundled into ES6 that make it easier to manipulate or access data in arrays.

There are plenty of different array helper functions out there, each with a specific use case, but for now we'll look at two examples: forEach() and map().

Here's how forEach() works:

let arrayOfFruits = ["Apples", "Oranges", "Bananas"]; 

arrayOfFruits.forEach( fruitItem => console.log("I like " + fruitItem);

//Will print out: 

//I like Apples
//I like Oranges
//I like Bananas

This is nifty for when you need to iterate through all the items in an array and perform some kind of functionality to each.

The next example that developers often use is map() which allows you to take each item in an array and pass it through a function – map() also returns the new array (where each of the items has been mutated by the function you define).

Here's how it works:

//Base array (before map)
let people = [ {name: "Ben", occupation: "Developer"}, {name: "Sarah", occupation: "Manager"}]; 

//mapped array
let occupations = people.map( person => person.occupation ); 

// prints out: ["Developer", "Manager"]; 

The mapping function, person => person.occupation, says that for each person object in the array, return the String that corresponds to that person's occupation and put it our new array.

The map() function (and its siblings filter() and reduce()) are incredibly useful for manipulating object-based arrays, like you see in the example above. They offer a concise, readable syntax that's preferable over the equivalent code that uses for or while loops.

The Bottom Line

JavaScript is the core of our online world.

It runs our browsers, it runs any services or tools we use on the daily, and it's even rendering this article right now for you to read.

As web developers, a major tenet of our work is using JavaScript and all of its many features as best we can.

Luckily, the most recent update to JavaScript (ES6) made coding with JavaScript way easier – it introduced a ton of new features and syntax that allow web developers to program more efficiently.

If you're interested in web development as a career, it's a great idea to learn what ES6 can do – it will help you write cleaner, simpler, but more powerful code.

Did I miss any key features from ES6 that you like to use? Let me know in the comments below!

  • Save

Leave a Reply

Share via
Copy link