ES6 Interview Questions and answers

Essential ES6, ES7 and ES8 interview questions and answers.

Updated on 12/09/18
9 minute read

Disclosure

Webquestions.co is a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for us to earn fees by linking to Amazon.com and affiliated sites. As an Amazon Associate I earn from qualifying purchases.

JavaScript is always evolving and new features are introduced on a regular basis. ES6 is definitely one of the major changes the language undertook over the last decade. Here is a list of JavaScript questions related to the latest features of the language. Keep reading. 

Getting familiar with the language new features is not always an easy task. Hope this questions will help you do that. I will try to add as much ES6 interview questions asked in real interviews as I can. If you have some, feel free to share in the comments. Happy Hacking!

Try these:

 

Question #1: Explain the `let` keyword, give an example of why it is fundamentally different than the `var` keyword.

A common and very basic ES6 interview question. Tackles the new approach to variables and how they behave. 

Answer:

let keyword introduced in ES6. It mainly provides a way to declare and use variables in block-scope. The var keyword is function scoped. meaning a variable declared using the var keyword is scoped to the entire function in which it was declared. How let is different than var is best explained by examples.

access a variable before it is declared:

Possible:

console.log(y);

var y = 5; //undefined.


The variable `y` is hoisted and set to undefined and can be accessed by the log() call.

Not Possible:

console.log(y);

let y = 5; //error - y is not defined.

 

The variable y is declared using let. It is only accessible to code that is 'below' it scope-wise.

Block scope vs. function scope:
We change the var keyword to let.

 

let x = 1984;
(function(){
    if (false) {
        let x = 1948; //scoped declaration
    }
    console.log(x); //1984
}());


 

Now the let inside the IF statement will not be scoped to the IIFE so when the log() invocation is run, the 'x' available is the one declared outside the IIFE. The x declaration inside the IF statement is block-scoped and will not effect outer scopes.

 

Question #2: Suggest one simple way of removing duplicates from an array

Answer:

Using the Set() object. Here is an example of an array with duplicates and the use of Array.from() to return data as an array since Set()'s instance is an object.

const array = [1, 4, 99, 3, 1, 4, 15];

const noDups = Array.from(new Set(array));

console.log(noDups); //[1, 4, 99, 3, 15]


Question #3: Explain ES6 `Symbol()`. Provide one use case and explain how can a `Symbol()` be coerced to `String`.

The subject is a must know question for an ES6 interview.

Answer:

`Symbol` is a new primitive type introduced in ES6.

let mySymbol = Symbol();

typeof mySymbol; // 'symbol'

 

A Symbol is created by the factory function `Symbol()`. The factory function can be passed an argument that serves as a description, mainly for debugging purposes.


 

let mySymbol = Symbol();

let mySymbol2 = Symbol('mySymbol');

 

 There is no constructor function for Symbol, and trying to instantiate one will throw an error.

let sym = new Symbol(); //Uncaught TypeError: Symbol is not a constructor

 

Each Symbol has a unique ID and will not clash with other Symbols, even if passed the same description. 

 

let s1 = Symbol();
let s2 = Symbol();
let s3 = Symbol('description');
let s4 = Symbol('description');

s1 === s2; //false
s3 === s4; //false

 

Since Symbols have a unique ID and will not clash with other Symbols, one good use it property keys and method definitions.

let mySymKey = Symbol();
let mySymMethod = Symbol();

let object = {

    [mySymKey]: "value",
    [mySymMethod]() {
       return "some actions";
    } 

}

console.log(object[mySymKey]); //"value"
console.log(object[mySymMethod]()) //"some actions"

Coercing a Symbol to string will throw an error:

let sym = Symbol("string");

let string = "some string";

let newString = string + sym; //Uncaught TypeError: Cannot convert a Symbol value to a string

Either use String factory or the toString() method.

 

    let newString = string + sym.toString();

    let newString = string + String(sym);

 

Related Links: MDN Symbol()


Question #4: Explain the Object related methods getOwnPropertyNames() and getOwnPropertySymbols()


ES6 introduced Symbol(), a new primitive type. `Symbol()` can also be used as an object property keys. 

Answer:

This is best explained by an example. Consider the following object. Some of its properties are string named properties, some are symbols and some are functions. 

let sym = Symbol('myKey');
let obj = {

    [sym]: "I am the value of the symbol key",
    a: 4,
    method() {
        return 99;
    }

}

console.log(obj); //{a: 4, Symbol(myKey): "I am the value of the symbol key", method: ƒ}

The methods are 2 ways of returning the property names (the keys) of the object. `getOwnPropertyNames()` will return an array of the properties without the symbols. `getOwnPropertySymbols()` will return the symbol properties.
Using the same object we created in the previous code example:

Object.getOwnPropertyNames(obj)
// ["a", "method"]

Object.getOwnPropertySymbols(obj)
// [Symbol(myKey)]

 

Question #5: Why arrow functions are different than "regular" JavaScript functions?


ES6 suggests an improved way of doing that using arrow functions. Explain why arrow functions are different an give a code example for keeping the 'this' reference using an arrow function.


Answer:


Arrow functions are an improvement comparing to ES5 and prior, first because they are less verbose. You code less when using them. A second reason is the arrow function uses the 'this' of its lexical content. Losing the 'this' is a common scenario if you developed in ES5 and previous versions before. Though there are patterns to overcome it, ES6 offers 'off the shelve' solution.

Now let's see code examples of the arrow function in action.

A function that returns a function.

prior to ES6, no arrow function:

var myObj = {

    run: function() {
        return function() {
            console.log(this);
        }
    }

}

myObj.run()(); //it will log the window object and not myObj context.


A common pattern to keep the reference to `myObj` context is to use `var self = this` in the desired context and keeping it available in the scope.

var myObj = {

    run: function() {
       
        var self = this;       
 
        return function() {
            console.log(self);
        }
    }

}

myObj.run()(); //it will log the myObj object, we kept the 'this' reference to the object.


ES6, arrow function:

We can skip the `var self = this;` and just return an arrow function. The latter will keep the reference to the desired 'this'.

var myObj = {

    run: function() {
        
        return () =>  //notice the syntax. 
            console.log(this);
    }

}

myObj.run()(); //it will log the myObj context and not window object.


This example might not be 100% real life case but I hope it helps to understand the point.

 

Strict mode and forcing 'this'.

In strict mode, for example, If you were to declare a function and not define it's 'this', the JavaScript engine will not force it to be the window object and it will be set to undefined. Let's see an example:

prior to ES6, no arrow function:

'use strict';

   var functionProperty = function(){
        console.log(this);
    }

functionProperty(); //undefined


If we would declare the function as an arrow function, the 'this' reference will be kept (to the window object in this specific case) with no need to pass it. See the following code example:

ES6, arrow function:

'use strict'

   var functionProperty = () => { //notice the syntax
        console.log(this);
    }

functionProperty(); // {Window}

There are more examples of the above when arrow functions are a more suitable solution than 'regular' JavaScript functions, experiment with it and learn new powerful tool you can use.

 

Question #6: How can we use the ES6 spread operator instead of `apply()`?


We can use Javascript's `apply()` to pass an array to a function that requires one or more separate arguments.  Explain how can we use the spread operator instead of `apply()`.

Answer:


console.log(Math.min(...[4,8,5])); //4 


The spread operator will spread the array to single separated values and those can be passed to methods such as `Math.min()`.


 

Question #7: `const` declaration of a string


What will be logged to the console?

const x = "some string";

x = "other string";

console.log(x);

 

Answer:


Nothing, a `TypeError: Assignment to a constant variable.` an error will be thrown. Since we used the keyword `const` to declare our variable, or constant in other words, we can not re-assign another value to it. Be careful, The name may be a little misleading since in other cases what was declared with the `const` keyword, is mutable or parts of it are. 

Related Link: MDN - const

 

Question #8: Explain Async/Await, how it works and how it provides different feel and syntax than using Promise callbacks.

Real interview question and answer asked in JavaScript interview by Opinya Solutions

Answer:


Async functions were introduced in ES8 and serve as a new feature for cleaner handling of Promises responses, errors and more. 

Main Benefits of using Async/Await:

  1. Less code.
  2. Synchronous feel for asynchronous code.
     

Let's see an example of using Promises without Async functions. 

Assume there is a function named `getData()` that returns a promise, after 3 seconds, with the string "data" as our data. We would like to log the data to the console. Pretty simple scenario.  
The function that returns the promise: 

const getData = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("data");
    }, 3000);
  });
}

Now let's log the result to the console using `then` method:

const makeAsync = () => {

    getData().then(data => { 
        console.log(data);
    });

}

makeAsync(); //"data" after 3 seconds.

What we have here is a typical way of using data returned form promise. Let's see how the same behavior can be implemented using Async function and `await`.

const makeAsync = async () => {
  const result = await getData();
    console.log(result);
  
}

makeAsync();

You can see that using Async function is less code and has a feel of synchronous function.

This is a basic usage example. There is more to Async functions. Here are some links for further reading:

MDN async functions
6 Reasons Why JavaScript’s Async/Await Blows Promises Away

 

Question #9: Explain Destructuring assignment - What will be the values of the variables?

What will be the value of `a` and `b`?

const array = [5, 7, 20];

let [a, b] = array;

 

Answer:

The values will be `5` and `7` respectively. 

This is called "destructing assignment" and what it does is using the values from the array to set the two separate variables declared. This can be very useful in some cases. I recommend reading more about it: MDN - Destructuring assignment.

 

Question #10: Propose a newer way to determine if an array contains a certain element.

A common way of knowing if an array contains a certain element is using `indexOf()`. 

Here is an example:

var myArray = [3, 6, "word", "text"]; //our array

myArray.indexOf(3); //0

myArray.indexOf(6); //1

myArray.indexOf("text"); //3

`indexOf();` returns the index position of the passed value.

This works great and we can work with the returned index to accomplish whatever it is we are trying to accomplish.

Propose a newer way (ES6 and above) of finding if a value or an element exists in an array.

Answer:

One way of doing that is using the Array.prototype.includes().

The method returns a boolean and not the index. 

Here is an example of the workings of the method:

let myArray = [3, 6, "word", "text"]; //our array

myArray.includes(3) //true

myArray.includes(55) //false

myArray.includes("word") //true

myArray.includes("Word") //false

Few gotchas and points:

  • JavaScript is case sensitive. Make sure you remember that when looking for a string in the array. 
  • `includes()` do find `NaN` types while `indexOf` does not.
  • `includes()` returns a boolean

 

Question #11: for...of, arrays and objects.

ES6 introduced the for...of loop. 

Here is a use case:

let array = [1, 2, 3, 4, 5];

for (a of array) {

    console.log(a);

}

//1
//2
//3
//4
//5

What if I ran for...of on an object, what would be the outcome? 

If you think it will not work, explain why.

Here is the question code example:

let object = {

    a: "1",
    b: "2",
    c: "3",
    d: "4"

}

for (a of object) {

    console.log(a);

}

 

Answer:

An error will be thrown. 

Uncaught TypeError: object is not iterable

Not all objects in JavaScript are iterable. Array and Map are examples of iterable objects (or types).

I recommend reading the following The iterable protocol page for more information. 

 

Question #12: Explain what are Template literals (Template strings).

Explain why it is different than the old JavaScript strings, what the feature provides us as developers.

 

Answer:

Templates are a new way of looking at JavaScript strings. 

There are a few differences. Templates literal are more flexible solutions and allows you, the developer, more freedom and convenience when handling strings. 

Here are the differences:

Syntax

Template strings are enclosed by the back-tick (`). Just to refresh your memory, the other strings are closed either by double-quoted or single-quote character (" or ').

let goodOldString = "Hello!";// or using singlequote ' '

let templateString = `Hello template...`;

 

Multi-line strings

As you may already know, the following multi-line string definition in JavaScript will throw an error.

let tryThis = "Here is a multi - 
                  Line string, It is easier to read.";

Why is that? JavaScript parser will encounter the "new line" character before it encountered a closing double quotes character. The parser is designed to throw an error since it considered it as an unclosed string, and those can't live inside a code. 

Template strings allow us to do just that. See how it works in the following code snippet.

let tryThis = `Here is a multi - 
                  Line string, It is easier to read.`; 
//notice the back-tick.

Another cool thing this feature allows is -

Expression interpolation

Basically, it allows you to use expressions within the string instead of concatenating like crazy. 

Here is a classic way of using a variable in a string:

let name = "John";

let concatString = "My name is:" + " " + name;

console.log(concatString); //My name is: John

With template strings, it can be done as part of the string itself.

let name = "John";

let interString = `My name is: ${name}`;

console.log(interString); //My name is: John

It is done with ${}.

Let's take it one step further - can I interpolate function statement? Take a moment to think about that. The answer is in the following example.

function sum(a, b) {
    return a + b;
}

let interString = `2 + 2 is equal to ${sum(2, 2)}`;

console.log(interString); //2 + 2 is equal to 4

It is possible. It is easier to create dynamic strings. 

Read more about Template literals on MDN.

 

Question #13: Redeclaring a variable using 'let'.

Redeclaring the same variable prior to ES2015 was possible as follows:

//assume the same scope

var someString = "this is the first declaration";

// some code later...

var someString = 1999;

console.log(someString); //1999

 You can see that I could easily overrun or redeclare the same variable. 

This can cause some nasty problems. 

My question to you is: Is the following example using 'let' also possible?

//assume the same scope

let someString = "this is the first declaration";

// some code later...

let someString = 1999;

console.log(someString);

 

Answer:

No. It is NOT possible. 

The JavaScript parser will not allow you to declare the same variable name in the same scope. 

This is a good thing. It can help to prevent other people (or yourself) from using the same variable names and by that, kill your code.

 

Final Thoughts and further resources

ES6 is gaining a lot of momentum over the last few years. ES5 and prior versions slowly become obsolete. 

Improving your skills with ES6 interview questions is highly recommended if you want to stay up to date with the newest technologies and frameworks.

Answering JavaScript interview questions will help you to stay market relevant as a developer.

Other resources: