ECMAScript 6 Features (ES6) – Functions, Objects & Classes

Note: This is part 2 of three-part series An Overview of ECMAScript 6 (ES6) Syntax & Features series. This learning post is still in active development and updated regularly.

In the previous learning-note post An Overview Of Common ECMAScript 6 (ES6) Syntax & Features, basic ES6 syntax such as let, const, map, sets, for..of etc with simple use case examples were discussed.

Modern JS is also known as ES6 and its features are heavily used in JS frameworks like React, VueJs, Angular etc. In this learning-note series, following key ES6 features are discussed.

Article Series
Part 1: Basic Syntax
Part 2: Functions, Objects & Classes (this post)
Part 3: Asynchronous Features

The purpose of this series to overview ES6 features & syntax introduced in JS functions, objects and Classes with simple use case examples.

The definitions used in the following section is directly lifted from the MDN web documents here. They should be considered as quote.

ES6 Functions & Classes

1. Arrow Functions
An arrow function expression has a shorter syntax than a function expression and does not have its own <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this">this</a>, <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments">arguments</a>, <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super">super</a>, or <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new.target">new.target</a>. These function expressions are best suited for non-method functions, and they cannot be used as constructors.
Basic Syntax
//arrow function syntax
    () => { ... } // with no parameter
     x => { ... } // with one parameter
(x, y) => { ... } // with several parameters
Basic Example
//Basic examples
//syntax - with no argument
() => { statements }

//ES5 syntax
let myFunc = function jsLearn() {
    return 'Welcome to ES6 features';
    };

//ES6 syntax
let myFunc = () => { return 'Welcome to ES6 features' };

The parameter list for a function with no parameters should be written with a pair of parentheses ( ). A parenthesis is required if there are no parameters.

Examples with multiple lines
// ES5 function syntax
function welcome() {
    return 'Welcome to ES6';
  }

  // ES6 arrow function syntax with return
  const welcome = () => {
    return 'Welcome to ES6';
  }

  // ES6 arrow function without return
  const welcome = () => `Welcome to ES6`;

  //ES6 with parameter
  const welcome = (name) => `${name}, Welcome to ES6`;

 //function call
  welcome('John'); // John, Welcome to ES6.

The regular function (lines: 13-15) above can be written as the arrow ( => ) function (Lines: 18-20). When the only statement in an arrow function is return, the return and the surrounding curly brackets can removed (line 23).

Note: This topic is discussed in detail in another post understanding JavaScript arrow function.

Additional Information: Arrow functions | MDN Web Docs

2. Default Parameters
Basic Syntax
//basic syntax
function [name]( param1, param2= defaultValue) {
  // statements
}
Basic example

If default parameters in a function are not defined it defaults to undefined. To set a default value, first it has to be tested whether parameter value is not undefined (line 3), then only assign a value.

//ES5
function add(a, b) { 
   b = (typeof b !== 'undefined') ? b : 1;  
   return a * b; 
 } 
 add(5, 2); //10
 add(5); // 5 

//ES6
function add(a, b = 5) { 
  // b is 5 if not passed (or passed as undefined) 
   return a + b;    
} 
//functional call
add(10); //15

With ES6 default parameter syntax, such test parameters are not required and a default value can be set directly (line 14)

Additional Information: Default parameters | MDN Web Docs

3. Enhancing Object Literals

JavaScript objects are initialized using the literal notation (initializer notation). An object initializer is “a comma-delimited list of zero or more pairs of property names and associated values of an object, enclosed in curly braces ({})“.

In ES6, shorter notations (shorthand) were introduced to achieve the same results. ES6 shorthand syntax for property names, method definitions and computed property names, which are briefly discussed below.

3.1. Shorthand Property Names

Basic Syntax
//ES5
const topic = "Es6 Syntax";
const ES6 = { topic: topic };
console.log(ES6); //{topic: "Es6 Syntax"}

//ES6
const topic = "Es6 Syntax";
const ES6 = {topic}
console.log(ES6); //{topic: "Es6 Syntax"}

In ES6 syntax, the line 3 notation (under ES5) can be written with a shorter notation (line 8) and get the exact same result. The ES6 syntax much simple & easy to read.

Additional Information: Object initializer | MDN Web Docs

3.2. Shorthand Methods

With ES6, shorter syntax for method  (function assigned to the method’s name) definitions on object initializer is introduced.

Basic Syntax
//ES5
const objectName = {
  property: function (parameters) {}
};

//ES6
const objectName = {
  property(parameters) {}
};

In ES6 syntax use of :function keyword has been omitted and its no longer required.

Basic Example
//ES5
let toDoList = {
  learn: function() {
    console.log('Learn React router this weekend.');
  },
  write: function() {
    console.log('Write a blog post.');
  }
};
//retrieve values
toDoList; //OUTPUT => {learn: ƒ, write: ƒ}
toDoList.learn();//OUTPUT => Learn React router this weekend.
toDoList.write();//OUTPUT => Write a blog post.

With ES6 syntax, the :function keyword (lines: 3 & 6) from the above code were removed which makes it much simpler and get the exactly same out.

//ES6
let toDoList = {
  learn() {
   console.log('Learn React router this weekend.');
  },
  write() {
    console.log('Write a blog post.');
  }
};

Additional Information: Method definitions | MDN Web Docs

3.3. Computed Property Names

Object initializer syntax allows you to put an expression in brackets [], that will be computed and used as the property name.

Basic Syntax
//basic syntax
let x = 'Hello';
let y = {
  [2 + 2]: 'makes four.',
  [x]: 'World'
};
console.log(y); //OUTPUT => {"makes four.", Hello: "World"}
Basic Example
//ES5 syntax
 const myObj = {Subject: 'React'}
 const topic = 'Topic'
 myObj[topic] = 'Components'
 console.log(myObj); //OUTPUT => {Subject: "React", Topic: "Components"}

//ES6 syntax
 const title = 'Subject';
 const myObj = {[title]: 'React', Topic: 'Components'};
 console.log(myObj); ////OUTPUT => {Subject: "React", Topic: "Components"}

In the example above, to use topic variable as a property name (line 4), it has be first define topic variable (line 3) before its use.

With the ES6 syntax (lines: 8-10), expression in [ ] square bracket (line 9) can be used directly and the calculated value of expression will be applied as its property name value.

Note: This topic is discussed in detail in another post Understanding Computed Property Names.

Additional Information: Computed property names | MDN Web Docs

4. Destructuring assignments

The destructuring assignment syntax makes possible to conveniently extract array values or object properties into distinct variables.

Basic Syntax
//basic syntax
const x, y, rest;
[x, y] = [5, 10];
//retrieve
console.log(x); // 5
console.log(y); // 10

//assigning with ..rest pattern
[x, y, ...rest] = [5, 10, 15, 20, 25];
console.log(x); // 5
console.log(y); // 10
console.log(rest); // [15, 20, 25]
Basic Examples

The object and array literal expressions provide an easy way to create ad hoc packages of data.

4.1. Object Destructuring

A variable can be assigned its value with destructuring separate from its declaration.

//ES5
const framework = {
    title: 'React',
    version: 16.7,
    description: "Current stable verson",
    topics: ['JSX', 'Component', 'Prop', 'State' ]
}
//retrieve
console.log(framework.title); // React
console.log(framework.version); // 16.7

To retrieve title & version with ES6 syntax is much simpler.

//ES6
const {title, version } = {
    title: 'React',
    version: 16.7,
    description: "Current stable verson",
    topics: ['JSX', 'Component', 'Prop', 'State' ]
}
//retrieve
console.log(title); // React
console.log(version); // 16.7

The title and version property names are added as variable parameters (line 12) and the same parameters can be used to retrieve their values in the console.log (lines: 19-20).

Additional Information: Array destructuring | MDN Web docs

4.2. Array Destructuring

Array desctructuring has similar syntax with that of object desctructuring.

//ES5
const subjects = [ 'WordPress', 'Gutenberg', 'React', 'Vue', 'Angular' ]

//retrieve 1st & 4th items
subject[0]; //WordPress
subject[3]; // Vue

With ES6 destructuring assignment uses similar syntax on the left-hand side of the assignment to define what values to unpack from the sourced variable.

//ES6 - array destructuring
const [first, fourth]= ['WordPress', 'Gutenberg', 'React', 'Vue', 'Angular']

//retrieve 
 console.log(first); // WordPress
 console.log(fourth); // gutenberg

//retrieve 1st & 4th item
const [first,,, fourth,]= ['WordPress', 'Gutenberg', 'React', 'Vue', 'Angular']
console.log(first); // WordPress
console.log(fourth); // Vue

Some returned values can be ignored with comma ( , ) for each item as shown in line 15.

Additional Information: Object destructuring | MDN Web docs

5. Generators

The <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator" target="_blank" rel="noopener">Generator</a> object is returned by a generator function and it conforms to both the iterable protocol and the iterator protocol.

Generators are new types of functions that can be paused in the middle of its execution to be resumed later. They are recognized with * immediately followed by function keyword (eg. function*). It can be paused using yield keyword and and can be used repeatedly calling next().

Basic Syntax
//basic syntax
function* gen() { 
  yield 1;
  yield 2;
  yield 3;
}

var g = gen(); // "Generator { }"
Creating Generator

Create a generator function named director to countdown the three yield expressions with the next() method returns. The ES6 next() replaces yield expression.

//create a generator function
 function* director() {
    yield "ES6"
    yield "React"
    yield "Vue"
    yield "action";
 }
//store in a variable action
  const action = director();
 
//retrieve value
  console.log(action.next);
  console.log(action.next);
  console.log(action.next);
  console.log(action.next);
  console.log(action.next);
 
//OUTPUT
 Object { value: "ES6", done: false }
 Object { value: "React", done: false }
 Object { value: "Vue", done: false }
 Object { value: "action", done: false }
 Object { value: undefined, done: true }

The director() generator function is stored in a variable action (line 9) and retrieve its value. Each time yield statement is used the function has to be restarted with next() method which jumps to next yield expression. The console.log has to be restored five different times to return five yield statement. Once terminating value is reached, the next() return {done: true}.

Creating Generator Functions

Generator function are commonly applied to create an array iterator,  to create sequence of finite or infinite values.

// define generator function
 function* eachItem(arr) {
    for(var i=0; i< arr.length; i++) {
      yield arr[i];
    }
 }
// assign array and pass  
 const letters = eachItem(["Class", "Literals", "Rest", "Promise", "Spread"]);
 const abcs = setInterval(function(){
   const letter = letters.next();
     if(letter.done) {
	clearInterval(abcs);
	   console.log("Now I know my ES6 Syntax");
     } else {
	   console.log(letter.value);
     }
  }, 300);
//OUTPUT
Class
Literals
Rest
Promise
Spread
Now I know my ES6 Syntax

In the example above a simple generator function eachItem is created

Additional Information: Iterators and generators | MDN Web Docs

6. Symbols

The Symbol() function returns a value of type symbol, has static properties that expose several members of built-in objects, has static methods that expose the global symbol registry, and resembles a built-in object class but is incomplete as a constructor because it does not support the syntax “new Symbol()“.  

Basic Syntax
//basic syntax
Symbol([description])

JS primitives are strings, arrays, objects, Boolean and numbers. Symbols, introduced in ES6, are new type of primitives, often used as unique IDs and  define customized iteration behavior. Symbols are used as unique identifier which don’t conflict with objects, keys that are string. Symbols are also help us to create customized iteration behavior.

Creating Symbol

Symbols are created using function factory. When a function returns an object, its called factory function. Its not a class or constructor but returns a new object without the use of new keyword.

// Create symbols
const symbol = Symbol('description')

In the example below, Symbol() factory function is assigned to an id (line 2).  In the courseInfoobject with title & topic properties, there is id property (line 6) too.

// assign id to symbol
const id = Symbol();
 const courseInfo =  {
    title: "ES6",
    topics: ["babel", "syntax", "functions", "classes"]
    id = "js-course";
 }; 

 // set value of ID & attach to couseIfo object
  courseInfo[id] = 54321; // unique number
  //console.log
  console.log(courseInfo[id]); // 54321
  //console log entire couseInfo object
  console.log(couseInfo);
  //OUTPUT
 {title: "ES6", topics: Array(4), Symbol(): 54321}
   title: "ES6"
   title: "ES6"topics: (4) ["babel", "syntax", "functions", "classes"]
   Symbol(): 54321
   __proto__: Object

In line 10, a symbol has been set up and with a unique id ID name. This is important because there is already another id key field “id”in the courseInfo object (line 6). This creates conflict because id symbol as well as id object key.

// console log courseInfo 
  console.log(courseInfo);
//OUTPUT
{title: "ES6", topics: Array(4), Symbol(): 54321}
    id: "Js-course"
    title: "ES6"
     title: "ES6"topics: (4) ["babel", "syntax", "functions", "classes"]
     Symbol(): 54321
    __proto__: Object

However, even after id is added, the symbol is intact and there is no naming conflict and no danger of overriding our data. Symbols can also be used as iterators (see example below).

Additional Information: Symbol | MDN Web Docs

7. Iterators

Iteration is one the most common programming task such as processing items in a collection which can be performed by using for loops, while loops and map().

Using the for..of statement a string object can be iterated as shown below.

// iteration of string with for..of 
const title = "React";
 console.log(typeof title); // string

//iteration with for..of loop
for (const x of title) {
  console.log(x);
}
//OUTPUT
R 
e
a
c
t

ES6 iterators & generators provide a mechanism to customize for..of loop.

The MDN Docs refers iterators as “any object which implements the Iterator protocol by having a next() method which returns an object with two properties: value, the next value in the sequence; and done, which is true if the last value in the sequence has already been consumed. If value is present alongside done, it is the iterator’s return value.”

Iterables are defined as objects which their own iteration behavior, such as what values are looped over in a for...of construct. Some built-in types, such as Array or Map, have a default iteration behavior, while other types (such as Object) do not.

Creating User-defined Iterator

An example of iterating an string and creating an user-defined iterables.

// initialize title
 const title = "React";
 console.log(typeof title); // string

Now lets modify the code in console.log and make the code iterable by chaining with [] square bracket and adding Symbol.iterator inside square bracket. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/iterator" target="_blank" rel="noopener">Symbol.iterator</a> is an method which returns the default iterator for an object.

// using Symbol.iterator 
 console.log(typeof title[Symbol.iterator]); // function

An iterator object can be iterated explicitly by repeatedly calling next() and when it reaches its terminal value it returns {done: true}.

//ES5
const iterateIt = title[Symbol.iterator]();
console.log(iterateIt.next());
console.log(iterateIt.next());
console.log(iterateIt.next());
console.log(iterateIt.next());
console.log(iterateIt.next());
console.log(iterateIt.next());

//OUTPUT
{value: "R", done: false}
{value: "e", done: false}
{value: "a", done: false}
{value: "c", done: false}
{value: "t", done: false}
{value: undefined, done: true}

It is looping through an string when there are more letters that are part of this string the done: false but when it reaches end of the string and out of items iterating the done: true.

Creating a Customized Iterator

The following is simple example of creating a (customizable) user-defined iterables:

// initialize learningTopic function
function learningTopics(arr) {			
  var nextIndex = 0;	
    return {	
       next() {		
        if(nextIndex < arr.length) {
          return {value: arr.shift(), done: false}
        } else {		
          return {done: true}	
        }	
      }		
    }	
}
// initialize studyList array 
var studyList = ['ES6', 'ES6 Class', 'ReactJs', 'JSX'];
var iterateList = learningTopics(studyList);

// retrieve using next() method
console.log(`I am ready to study ${iterateList.next().value}.`);
console.log(`I am ready to study ${iterateList.next().value}.`);
console.log(`I am ready to study ${iterateList.next().value}.`);
console.log(`I am ready to study ${iterateList.next().value}.`);
console.log(`Is this finished? ${iterateList.next().done}`);

//OUTPUT
I am ready to study ES6.
I am ready to study ES6 Class.
I am ready to study ReactJs.
I am ready to study JSX.
Is this finished? true

Here our own iterator is defined using Symbol.iterator which will be useful in creating customized function to iterate some items.

Note: Conditional statements including use of for..of loop is discussed in a previous learning-note post Understanding JavaScript For Loops.

Additional Information: Iterators and generators | MDN Web Docs

8. Getters & Setters

The getter and setter are methods (functions)that get and set values of object properties known as accessor properties (different tha data properties).

Basic Syntax
//Basic syntax
const objName = {
  //getter
   get propName() { ... } 
  //expression for computed property name
   get [expression]() { ... } 

  //setter
   set propName(value) { . . . }
  //expression for computed property name
   set [expression](value) { . . . }
}

The getters and setters are defined using object literal syntax. The setters are used in conjunction with getters to create a pseudo-property (internal or “virtual” variable).

An Example

The getters method gets the value of a specifici property while setters method sets the value of a property. The get method does not take parameter, the set method takes single parameter.

//Getters & Setters
const learn = {
  topic: 'ES6',
  get js() {
      return `Learning ${this.topic}`;
  },
  set js(val) {
      this.topic = val;
  }
}

console.log(learn.js); // OUTPUT => Learning ES6

 // set js is executed with new 'React' value
learn.js = 'React';
 
console.log(learn.js); // OUTPUT => Learning React

The above examples illustrates creating an customized learn object with an additional new user-defined internal js property (lines: 7, 15).

Note: This topic is discussed in detail in another post Understanding JavaScript Accessors: Getters & Setters.

Additional Information: Defining getters and setters | MDN Docs

ES6 Classes

JavaScript classes are “special function” which can be defined as class expression or class declaration similar to to defining function.

1. Defining Classes
Basic Syntax
//class declaration
class name  {
  // class body
}

//class expression
var MyClass = class [className]  {
  // class body
};
Creating Class

In the example below, a learnJs() function (line 2) with two properties (topic, section) was created. Using object.prototype._ a reminder() method (line 7) was also created. Lastly, learnES6 object instance was created (line 11) using new keyword and expected output was displayed (line 12).

//ES5 -- Initialize function
function learnJs(topic, section) {
  this.topic= topic;
  this.section= section;
}
//method declaration
learnJs.prototype.reminder = function() {
  console.log(this.topic);
}
//create LearnJs instance
let learnES6 = new learnJs("Learning ES6 features");
//retrieve
learnES6.reminder(); //OUTPUT => Learning ES6 features

The above function can be written with ES6. The above learnJs object is initialized using class syntax with same properties and methods.

// ES6 -- initialize class
class LearnJs {
  constructor(topic, section) {
    this.topic = topic;
    this.section= section;
  }
// method declaration
  reminder() {
    console.log(this.topic);
  }
}
//Create learnES6 instance
let learnES6 = new LearnJs("Learning ES6 features");
learnES6.reminder(); //OUTPUT => Learning ES6 feature

The object instances created with new keyword also become a constructor instance as shown in the example above.

From the above two examples, we got the same output demonstrating that JS class are functions, but creating method with class keyword is much simpler (lines 16-28) and easier to read.

2. Class Inheritance

A class can be extended using extends keyword to create subclasses to inherit (share) properties defined in parent class.

Basic Syntax
//class declaration
class name [extends] {
  // class body
}
//class expression
var MyClass = class [className] [extends] {
  // class body
};

Its syntax is similar to basic class syntax with extends keyword.

Creating Inheritance Class

In subclasses, an object defined in parent class can be shared with subclass and its properties can be modified or added new ones.

// initialize learnJs class
class LearnJs {
  constructor(topic, section) {
    this.topic = topic;
    this.section= section;
  }
// define method
    progress () {
        return `I am making progress on ${this.topic} & ${this.section}`;
    }
}
//initialize subclass React with extends
class LearnReact extends LearnJs {
    constructor(topic, section, library) {
        super(topic, section);
        this.library = library;
    }
//define method
    explore () {
     return `I'm learning ${this.topic} & exploring ${this.library}.`;
    }
}
//initialize learnProgress object instance with new keyword
const learnProgress = new LearnReact('JavaScript','ES6','ReactJs');
//retrieve
console.log(learnProgress.progress());
//OUTPUT =>I am making progress on JavaScript & ES6 
console.log(learnProgress.explore());
//OUTPUT =>I'm learning JavaScript & exploring ReactJs.

In the above example, a subclass named LearnReact using extends keyword was created (line 13) from parent class LearnJs object (line 2). The subclass constructor function was initialized referring to its properties from parent class and an additional library variable (line 14). Properties from LearnJs (parent class) are referred using super keyword (line 15). The added libraryvariable added to the LearnReact subclass instance is defined using this.library = library (line 15).

Note: This topic is discussed in detail in another post Learning JavaScript Classes.

Additional Information: Classes | MDN Web Docs

Wrapping Up

In this learning to an overview of ES6 features & syntax introduced in functions, objects and classes are presented. Links to detail discussion on these topics and/or additional resources are provided at end of each topic.

Part 3: ECMAScript 6 Features (ES6) – Asynchronous Functions

Useful Resources and Links

While preparing this post, I have referred the following references extensively. Please to refer original posts for more detailed information.