Deeper look into ES6 new syntax and their behaviors

08 May 2021 13 mins

1. What is the difference between let and var?

  • var is function scoped and let is block scoped.
  • var is hoisted to the top of the function and let is not hoisted.
  • var can be re-declared and let cannot be re-declared.
  • var is initialized with undefined and let is not initialized.
  • var is attached to the window object and let is not attached to the window object.
  • var can be used before declaration and let cannot be used before declaration.
  • var is used to declare global variables and let is used to declare local variables.

2. Arrow function

Arrow functions are a new way to write functions in ES6. Arrow functions are a shorter syntax for writing functions. Arrow functions do not have their own this, arguments, super, or new.target. These functions capture the this value of the enclosing context.

2.1. Arrow function syntax

// ES5
var add = function(a, b) {
  return a + b;
}

// ES6
const add = (a, b) => a + b;

3. Spread operator

The spread operator allows an iterable such as an array expression or string to be expanded in places where zero or more arguments (for function calls) or elements (for array literals) are expected, or an object expression to be expanded in places where zero or more key-value pairs (for object literals) are expected.

3.1. Spread operator syntax

// ES5
var arr1 = [1, 2, 3];

var arr2 = [4, 5, 6];

var arr3 = arr1.concat(arr2);

console.log(arr3); // [1, 2, 3, 4, 5, 6]

// ES6

const arr1 = [1, 2, 3];

const arr2 = [4, 5, 6];

const arr3 = [...arr1, ...arr2];

console.log(arr3); // [1, 2, 3, 4, 5, 6]

4. Rest parameter

The rest parameter syntax allows us to represent an indefinite number of arguments as an array.

4.1. Rest parameter syntax

// ES5
function sum() {
  var args = Array.prototype.slice.call(arguments);
  return args.reduce(function(a, b) {
    return a + b;
  }, 0);
}

console.log(sum(1, 2, 3)); // 6

// ES6

function sum(...args) {
  return args.reduce((a, b) => a + b, 0);
}

console.log(sum(1, 2, 3)); // 6

5. Destructuring

Destructuring is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables.

5.1. Destructuring syntax

// ES5
var arr = [1, 2, 3];

var a = arr[0];
var b = arr[1];
var c = arr[2];

console.log(a, b, c); // 1 2 3

// ES6

const arr = [1, 2, 3];

const [a, b, c] = arr;

console.log(a, b, c); // 1 2 3

6. Template literals

Template literals are string literals allowing embedded expressions. You can use multi-line strings and string interpolation features with them. They were called “template strings” in prior editions of the ES2015 specification.

6.1. Template literals syntax

// ES5
var name = 'John';

var greeting = 'Hello ' + name + '!';

console.log(greeting); // Hello John!

// ES6

const name = 'John';

const greeting = `Hello ${name}!`;

console.log(greeting); // Hello John!

7. Default parameters

Default parameters allow named parameters to be initialized with default values if no value or undefined is passed.

7.1. Default parameters syntax

// ES5
function greet(name) {
  name = name || 'John';
  console.log('Hello ' + name + '!');
}

greet(); // Hello John!

// ES6

function greet(name = 'John') {
  console.log(`Hello ${name}!`);
}

greet(); // Hello John!

8. Object literal

Object literal is a comma-separated list of zero or more pairs of property names and associated values of an object, enclosed in curly braces.

8.1. Object literal syntax

// ES5
var name = 'John';

var person = {
  name: name,
  age: 30
};

console.log(person); // {name: "John", age: 30}

// ES6

const name = 'John';

const person = {
  name,
  age: 30
};

console.log(person); // {name: "John", age: 30}

9. Classes

Classes are a template for creating objects. They encapsulate data with code to work on that data. Classes in JavaScript are built on prototypes but also have some syntax and semantics that are not shared with ES5 class-like semantics.

9.1. Classes syntax

// ES5
function Person(name) {
  this.name = name;
}

Person.prototype.greet = function() {
  console.log('Hello ' + this.name + '!');
}

var person = new Person('John');

person.greet(); // Hello John!

// ES6

class Person {
  constructor(name) {
    this.name = name;
  }

  greet() {
    console.log(`Hello ${this.name}!`);
  }
}

const person = new Person('John');

person.greet(); // Hello John!

10. Modules

Modules are reusable pieces of code that can be exported from one program and imported for use in another program.

10.1. Modules syntax

// ES5

// file: person.js

function Person(name) {
  this.name = name;
}

Person.prototype.greet = function() {
  console.log('Hello ' + this.name + '!');
}

module.exports = Person;

// file: main.js

var Person = require('./person');

var person = new Person('John');


person.greet(); // Hello John!

// ES6

// file: person.js

export class Person {
  constructor(name) {
    this.name = name;
  }

  greet() {
    console.log(`Hello ${this.name}!`);
  }
}

// file: main.js

import { Person } from './person';

const person = new Person('John');

person.greet(); // Hello John!

11. Promises

A Promise is an object that may produce a single value some time in the future: either a resolved value, or a reason that it’s not resolved (e.g., a network error occurred). A Promise may be in one of 3 possible states: fulfilled, rejected, or pending. Promise users can attach callbacks to handle the fulfilled value or the reason for rejection.

11.1. Promises syntax

// ES5

// file: person.js

function Person(name) {
  this.name = name;
}

Person.prototype.greet = function() {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      resolve('Hello ' + this.name + '!');
    }.bind(this), 1000);
  }.bind(this));
}

module.exports = Person;

// file: main.js

var Person = require('./person');

var person = new Person('John');

person.greet().then(function(greeting) {
  console.log(greeting); // Hello John!
});


// ES6

// file: person.js

export class Person {
  constructor(name) {
    this.name = name;
  }

  greet() {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(`Hello ${this.name}!`);
      }, 1000);
    });
  }
}

// file: main.js

import { Person } from './person';

const person = new Person('John');

person.greet().then((greeting) => {
  console.log(greeting); // Hello John!
});

12. Generators

Generators are functions which can be exited and later re-entered. Their context (variable bindings) will be saved across re-entrances.

12.1. Generators syntax

// ES5

// file: person.js

function Person(name) {
  this.name = name;
}

Person.prototype.greet = function() {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      resolve('Hello ' + this.name + '!');
    }.bind(this), 1000);
  }.bind(this));
}

module.exports = Person;

// file: main.js

var Person = require('./person');

var person = new Person('John');

person.greet().then(function(greeting) {
  console.log(greeting); // Hello John!
});


// ES6

// file: person.js

export class Person {
  constructor(name) {
    this.name = name;
  }

  greet() {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(`Hello ${this.name}!`);
      }, 1000);
    });
  }
}

// file: main.js

import { Person } from './person';

const person = new Person('John');

person.greet().then((greeting) => {
  console.log(greeting); // Hello John!
});

13. Maps

Map objects are simple key/value maps. Any value (both objects and primitive values) may be used as either a key or a value.

13.1. Maps syntax

// ES5

var map = new Map();

map.set('name', 'John');

console.log(map.get('name')); // John

// ES6

const map = new Map();

map.set('name', 'John');

console.log(map.get('name')); // John