In our previous blog articles on our blog, we’ve covered mainly ECMAScript 5, but here, we’ll solely concentrate on ES6+. To reach out to previous blog posts, go here for Part 1 and here for Part 2. ES6 contains an ample number of new features so it can take days or pages to cover all of them, but we’ll, nevertheless, try to embark on this journey with this first article on ES6 and other subsequent standards.
Theory
What is ES6 and what determines the release of the new version of ECMAScript?
Answer: ES6 or ECMAScript 6 is the 6th edition of the JavaScript language that was released in June 2015. The new version is then released every year starting from 2015.
What is the difference between TypeScript and ECMAScript?
TypeScript is a strict syntactical superset of JavaScript, which adds optional static typing to the language; whereas ECMAScript is a scripting language specification created to standardize JavaScript.
What does 'use strict' mean in JavaScript?
‘use script’ defines a strict mode that helps to identify typical mistakes and prevent certain actions from being taken, thus a strict mode is a reduced and safer feature set of JavaScript. In ES5, the strict mode was optional, and in ES6 it’s needed for many of its features. Some tools will automatically add “use strict” on top of the file to force better writing of the JavaScript language.
Please, name the tool to convert ES6+ to ES5.
Answer: Since most of the browsers still support ES5, you might need a transpiler to convert ES6 to ES5. Babel is the most popular tool; it has various interfaces, like CLI, Node-module and an online converter. So, in order to transpile the examples in this article from ES6 to ES5, please use Babel online: https://babeljs.io/
What are some of the new features introduced in ES6?
Answer:
- Support for constants (immutable variables)
- Block-scope for variables, functions, and constants
- Arrow functions
- Destructuring assignment
- Extended Parameter Handling
- Template Literals and Extended Literals
- Enhanced Regular Expression
- Modules, Classes, Iterators, Generators
- Enhanced Object Properties
- Support for Map/Set & WeakMap/WeakSet
- Promises, Meta-Programming, Internationalization, and Localization
What are the ways to declare variables in JavaScript?
Answer: there are three ways to declare variables, with var, let, and const.
For example,
var width = 150; let height = 300; const key = 'abc123';
What is the difference between var, let, and const?
var declarations are globally or function/locally scoped; var can be re-declared and updated. let is block-scoped; can be updated, but not re-declared. const declarations are also block-scoped, but const can’t be updated and re-declared.
What is the block scope in ES6?
Answer: A block is a set of opening and closing curly brackets. Instead of using var, which declares variables attached to the enclosing function (or global if top level), scope uses let instead:
{ var a = 2; let b = 3; } console.log( a ); // 2 console.log( b ); // Uncaught ReferenceError: b is not defined
What is a constant?
A constant is a variable that’s read-only after its initial value is set. A const declaration must have an explicit initialization.
Example,
{ const a = [1,2,3]; a.push( 4 ); console.log( a ); // [1,2,3,4] a = 77; // TypeError! }
What is the spread/rest operator?
ES6 introduces a new operator, which is referred to as the spread or rest operator, depending on where and how it’s used.
The spread operator “spreads” the values in an iterable (arrays, strings) across zero or more arguments or elements. The spread operator can also be used in a function call.
function foo(x, y, z) { console.log( x, y, z ); } foo( ...[1,2,3] ); // 1 2 3
And
function foo(x, y, z) { console.log( x + y + z ); } let params = [1, 2, 3]; foo( ...params); // 6
If you need a function to work with an unknown number of parameters, the rest parameter comes in. The rest parameter (…), which is the same syntax as the spread operator, can take an indefinite number of parameters to a function. These parameters are available within the function as an array.
function mult(...args) { console.log( args.reduce(function(acc, currValue) { return acc * currValue; })); } mult(2, 4); // 8 mult(2, 4, 3); // 24
What is destructuring?
Destructuring is a new syntactic feature available in ES6, also referred to as a structured assignment. Destructuring makes it possible to unpack values from arrays, or properties from objects, into distinct variables.
For example,
var x = [1, 2, 3, 4, 5]; var [y, z] = x; console.log(y); // 1 console.log(z); // 2
What are the concise methods?
The concise method allows removing some redundant syntactic features that were present in ES5. Concise methods are used unless you need them to do recursion or event binding/unbinding, in this case, you should stick to ES5 syntax. Object super can only be used with concise methods.
For example, var obj = { fullName: function() { console.log(“This is a method”); } }
Will read in ES6 as:
var obj = { fullName() { console.log(“This is a method”); } }
Object super example:
var o1 = { foo() { console.log( "o1:foo" ); } }; var o2 = { foo() { super.foo(); console.log( "o2:foo" ); } }; Object.setPrototypeOf( o2, o1 ); o2.foo(); // o1:foo // o2:foo
What are the arrow functions?
The arrow function definition consists of a parameter list, followed by the => marker, followed by a function body, for example:
var foo = (x,y) => x + y;
If the arrow function is implemented with “concise body” (without { }), it does not need an explicit return statement. Note the omitted { } after the =>.
Arrow functions are always function expressions; there is no arrow function declaration. All the capabilities of normal function parameters are available to arrow functions, including default values, destructuring, rest parameters, and so on.
What are the advantages of using arrow functions?
- They are less verbose
- Arrow functions take this from their surroundings (lexical binding). Other lexical variables inside arrow functions: arguments, super, new.target
What is WeakMap in ES6?
WeakMaps are a variation of Maps but differ in how memory allocation works. WeakMaps take (only) objects as keys. The object references in the keys are held weakly, meaning that they are a target of garbage collection (GC) if there is no other reference to the object anymore. The WeakMap API is the same as the Map API. WeakMap keys are not enumerable. To have a list of keys, use a Map.
Example,
var m = new WeakMap(); var x = { id: 1 }, y = { id: 2 }; m.set( x, y ); x = null; // `x` is GC-able y = null; // `y` is not GC-able
What are generators?
A generator function allows a function to generate many values over time by returning an object which can be iterated over to pull values from the function one value at a time.
A generator can pause itself in mid-execution and can be resumed right away or at a later time. The generator function is declared with a new syntax:
function *foo() { // .. }
Generators also have a new keyword you can use inside them, to signal the pause
point: yield. Consider:
function *foo() { var x = 10; var y = 20; yield; var z = x + y; }
yield is not just a pause point. It’s an expression that sends out value when pausing the generator.
What is metaprogramming with proxies?
Proxies enable you to intercept and customize operations performed on objects (such as getting properties). They are a metaprogramming feature. A proxy is a special kind of object you create that “wraps" another normal object. You can register special handlers (aka traps) on the proxy object which are called when various operations are performed against the proxy.
In the following example, the proxy is the object whose operations we are intercepting and handler is the object that handles the interceptions. In this case, we are only intercepting a single operation, get (getting properties).
const target = {}; const handler = { get(target, propKey, receiver) { console.log('get ' + propKey); return 123; } }; const proxy = new Proxy(target, handler);
When we get the property proxy.foo, the handler intercepts that operation:
> proxy.foo
get foo
123
Practice
What will be printed in the console when running the following code?
var maxNumber = 7; for (var i = 1; i <= maxNumber; i++) { setTimeout(function() { console.log(i); }, 1000); }
Answer
7 times number 8 will be printed
In this case, the variable "i" becomes global and at the time of calling the callback, it will already be equal to 8.
In order to display numbers from 1 to 7 instead, you should use let:
for (let i = 1; i <= maxNumber; i++) { /* previous code */ }
Does this code work correctly?
const boy = { age: 7 } boy.age = 23;
Answer
The code will run without errors, since the object reference will remain the same.
Write a function to get the sum of the arguments in one line.
console.log(sum(5,7,3)); // 15
Answer
const sum = (...values) => values.reduce((p, c) => p + c, 0)
What will be the result?
const version = 'es6'; const modify = (literals, str) => literals[0] + str.toUpperCase(); console.log(modify `I use ${version} and es5`);
Answer
I use ES6
Rewrite class using ES6 syntax
var Chessman = function(type, cell) { this.type = name; this.move(cell); }; Chessman.prototype.move = function(cell) { this.cell = cell; };
Answer
class Chessman { constructor(type, cell) { this.type = type; this.move(cell) } move(cell) { this.cell = cell; } }
Rewrite code to avoid the callback hell
const printSec = (number, callback) => { setTimeout(() => { console.log(`${number} sec`) callback() }, 1000) } printSec(1, () => { printSec(2, () => { printSec(3, () => {}) }) })
Answer
Using Promise
const printSec = (number) => { return new Promise((resolve, reject) => { setTimeout(() => { console.log(`${number} sec`) resolve() }, 1000) }) } printSec(1) .then(() => printSec(2)) .then(() => printSec(3))
And using await
async function printAll(){ await printSec(1) await printSec(2) await printSec(3) } printAll()
How can you swap the values of two variables (x and y) without using any other variables?
let x = 1; let y = 2; [x, y] = [y, x]; console.log(x) // 2 console.log(y) // 1
Rewrite code using ES6 syntax
var skills = ['html', 'css']; var h = typeof skills[0] !== "undefined" ? skills[0] : 'html5'; var c = typeof skills[1] !== "undefined" ? skills[1] : 'css3'; var j = typeof skills[2] !== "undefined" ? skills[2] : 'es6'; var p = typeof skills[3] !== "undefined" ? skills[3] : undefined; console.log(h, c, j, p);
Answer
let skills = ['html', 'css']; let [h = 'html5', c = 'css3', j = 'es6', p] = skills; console.log(h, c, j, p);
Write a program to fetch Fibonacci numbers less than 100 using an iterator
Note: the Fibonacci Sequence is the series of numbers: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, . . . Each subsequent number is the sum of the previous two.
Answer
let fibonacci = { [Symbol.iterator]() { let pre = 0, cur = 1 return { next() { [pre, cur] = [cur, pre + cur] return { done: false, value: cur } } } } } for (let n of fibonacci) { if (n >= 100) break console.log(n) }
Create a generator that will output numbers from the range
Answer
function* range(start, end) { let num = start; while (num <= end) { yield num++; } } for (let num of range(3, 7)) { console.log(num); }
Conclusion
JavaScript is an amazing programming language that contains an infinite well of hidden-gem-features and surprises. If you have not yet read any of Kyle Simpson’s books on JavaScript, we highly advise you to start now. Some of the examples of these interview questions were adapted from his famous book series, You Don't Know JS, in particular, his magnum opus ES6 and Beyond.
We’ve written other articles on how to survive technical interviews, in case you might be interested, here are a few other suggestions:
Take Control of Your Tech Interview
Conducting a Better Technical Interview (in case you’re a tech recruiter)
The Importance of Showing Off Your Soft Skills
Coding Interview Tools for Conducting Tech Interview
How to Hire a Freelance Web Developer (for recruiters and entrepreneurs)