Top EcmaScript Features that every javascript developer should know

EcmaScript is the standardized scripting language that JavaScript (and some other languages, like ActionScript) implement.  If you think EcmaScript is a terrible name, you’re not alone.  Brendan Eich, the original developer of JavaScript, once wrote that the name EcmaScript sounds like a skin disease.  Naming aside, JavaScript is one of the most important languages in existence today.  Every browser has a JavaScript interpreter, JavaScript on the server is becoming ever more popular, and now it’s possible to use JavaScript for desktop (Chrome Apps), nativish mobile (PhoneGap) and native Windows 8 apps.  A new version of EcmaScript will have a broad impact on web development.

The current version of EcmaScript supported in modern browsers is ES5 (with some ES6 support).  ES5 drives a lot of developers mad.  Folks coming from the backend development space find ES5 lacks some pretty basic language features.  As such, several workarounds have emerged.  TypeScript is very popular in the .NET world (and here at Wintellect) and CoffeeScript is kind of a big deal™ in the Ruby community.  Both TypeScript and CoffeeScript provide syntactic sugar on top of ES5 and then are transcompiled into ES5 compliant JavaScript.  ES6 will tackle many of the core language shortcomings addressed in TypeScript and CoffeeScript.

1. Default Parameters in ES6

In ES6, we can put the default values right in the signature of the functions.

var calculateArea = function(height = 50, width = 80) {  
    // write logic
    ...
}

In ES5, we were using logic OR operator.

var calculateArea = function(height, width) {  
   height =  height || 50;
   width = width || 80;
   // write logic
    ...
}

2. Array helper functions

New cool helper functions appeared, which facilitate work with JS arrays in most useful cases. How many times did you implement logic like: filtering, checking if any or all elements meet the condition, or elements conversion? Probably very often. Now you have great language features to do the work for you. Here, in my opinion, are the most valuable functions:

Array.prototype.find mdn

find lets you iterate through an array and get the first element back that causes the given callback function to return true. Once an element has been found, the function immediately returns. It’s an efficient way to get at just the first item that matches a given condition:

let numbers = [1, 2, 3];
let oddNumber = numbers.find(x => x % 2 == 1);
console.log(oddNumber); // 1

You might think this is similar to filter (an ES5 method), but whereas filter always returns an array of matches (and will return multiple matches), find always returns the actual element.

Array.prototype.findIndex mdn

findIndex behaves very similarly to find, but instead of returning the element that matched, it returns the index of that element.

let people = ['jamie', 'jack', 'isaac'];
let jackIndex = people.findIndex(x => x === 'jack');
console.log(jackIndex); // 1

Array.prototype.entries mdn

entries is a function that returns an Array Iterator (mdn docs for interators) that can be used to loop through the array’s keys and values. entries will return an array of arrays, where each child array is an array of [index, value].

let people = ['jamie', 'jack', 'isaac'];
let entries = people.entries();
console.log(entries.next().value); // [0, 'jamie']
console.log(entries.next().value); // [1, 'jack']
console.log(entries.next().value); // [2, 'isaac']

We can also use the spread operator to get back an array of the entries in one go:

let people = ['jamie', 'jack', 'isaac'];
let entries = people.entries();
console.log([...entries]); // [[0, 'jamie'], [1, 'jack'], [2, 'isaac']]

Although I won’t mention them in any detail here, we also have the new keys (mdn) and values (mdn) methods, which return an iterator of the array keys and the array values respectively.

Array.from mdn

Array.from takes many forms, as the ES6 compat table shows, but its general function is to enable the creation of a new array from an array like object. As its first argument it can accept something that’s array like (has length and indexed items), along with iterable objects, like the newly added Set and Map in ES6.

Array.from('hello'); // ['h', 'e', 'l', 'l', 'o']

Array.from([1, 2, 3]); // [1, 2, 3]

let namesSet = new Set(['jamie', 'jack']);
Array.from(namesSet); // ['jamie', 'jack']

from can also take a second argument, which is a map function to be applied to each element:

Array.from([1, 2, 3], x => x * x); // [1, 4, 9]

Because the method can take array like objects, we can use it to generate arrays of values too:

Array.from({ length: 4 }, (val, key) => key); // [0, 1, 2, 3]

Each time the mapping function gets called, the val argument will be undefined, as this object has no actual values, but the key argument will be 0, then 1 and so on. This lets us generate arrays of numbers, but we can also return whatever we’d like from the mapping function:

Array.from({ length: 2 }, () => 'jack'); // ['jack', 'jack']

With its ability to take array like objects along with iterators, and a custom mapping function, Array.from is incredibly versatile.

 

3. Template Literals in ES6

In ES6, we can use a new syntax ${PARAMETER} inside of the back-ticked string.

var name = `Your name is ${firstName} ${lastName}.`

In ES5, we have to break string like below.

var name = 'Your name is ' + firstName + ' ' + lastName + '.'

 

4. Destructuring Assignment in ES6

To get a property of an object, we could do something like this:

var movieStar = {
  name: 'James Bond',
  nickname: 'Bond',
  profession: 'Federal Agent'
};

console.log(movieStar.name);
// James Bond

With the new hand, we can do something like this:

var movieStar = {
  name: 'James Bond',
  nickname: 'Bond',
  profession: 'Federal Agent'
};

let { name, profession } = movieStar;

console.log(name, profession);

// James Bond
// Federal Agent

With arrays

If we wanted, for example, to get the first item from array, we could do something like:

var mortalKombat = ['Scorpion', 'Liu Kang', 'Sub Zero', 'Johnny Cage'];

console.log(mortalKombat[0]);
// Scorpion

With the destructuring hand , we can do something like this:

let mortalKombat = ['Scorpion', 'Liu Kang', 'Sub Zero', 'Johnny Cage'];

let [user1, user2] = mortalKombat;

console.log(user1, user2);
// Scorpion
// Liu Kang

It is still possible to play a little more:

let mortalKombat = ['Scorpion', 'Liu Kang', 'Sub Zero', 'Johnny Cage'];

let [userA, , userB] = mortalKombat;
let [user, ...users] = mortalKombat;

console.log(userA, userB);
// Scorpion
// Sub Zero

console.log(user, users);
// Scorpion
// ['Liu Kang', 'Sub Zero', 'Johnny Cage']

5. Classes in ES6

We can create class in ES6 using “class keyword. Classes creation and usage in ES5 was a pain in the rear, because there wasn’t a keyword class.

class Profile {   
   constructor(firstName, lastName = '') { // class constructor
      this.firstName = firstName;
      this.lastName = lastName;     
   }  
    
   getName() { // class method       
     console.log(`Name: ${this.firstName} ${this.lastName}`);    
   } 
}
let profileObj = new Profile('Kavisha', 'Talsania');
profileObj.getName(); // output: Name: Kavisha Talsania

I am not going to show you example of ES5 class creation, because there are many flavors.

 

6. Arrow Functions in ES6

This is probably one feature I waited the most. I love CoffeeScript for its fat arrows. Now we have them in ES6. The fat arrows are amazing because they would make your this behave properly, i.e., this will have the same value as in the context of the function—it won’t mutate. The mutation typically happens each time you create a closure.

Using arrows functions in ES6 allows us to stop using that = this or self = this or _this = this or .bind(this). For example, this code in ES5 is ugly:

var _this = this
$('.btn').click(function(event){
  _this.sendData()
})

This is the ES6 code without _this = this:

$('.btn').click((event) =>{
  this.sendData()
})

Sadly, the ES6 committee decided that having skinny arrows is too much of a good thing for us and they left us with a verbose old function instead. (Skinny arrow in CoffeeScript works like regular function in ES5 and ES6).

Here’s another example in which we use call to pass the context to the logUpperCase() function in ES5:

var logUpperCase = function() {
  var _this = this

  this.string = this.string.toUpperCase()
  return function () {
    return console.log(_this.string)
  }
}

logUpperCase.call({ string: 'es6 rocks' })()

While in ES6, we don’t need to mess around with _this:

var logUpperCase = function() {
  this.string = this.string.toUpperCase()
  return () => console.log(this.string)
}

logUpperCase.call({ string: 'es6 rocks' })()

Note that you can mix and match old function with => in ES6 as you see fit. And when an arrow function is used with one line statement, it becomes an expression, i.e,. it will implicitly return the result of that single statement. If you have more than one line, then you’ll need to use return explicitly.

This ES5 code is creating an array from the messages array:

var ids = ['5632953c4e345e145fdf2df8','563295464e345e145fdf2df9']
var messages = ids.map(function (value) {
  return "ID is " + value // explicit return
})

Will become this in ES6:

var ids = ['5632953c4e345e145fdf2df8','563295464e345e145fdf2df9']
var messages = ids.map(value => `ID is ${value}`) // implicit return

Notice that I used the string templates? Another feature from CoffeeScript… I love them!

The parenthesis () are optional for single params in an arrow function signature. You need them when you use more than one param.

In ES5 the code has function with explicit return:

var ids = ['5632953c4e345e145fdf2df8', '563295464e345e145fdf2df9'];
var messages = ids.map(function (value, index, list) {
  return 'ID of ' + index + ' element is ' + value + ' ' // explicit return
})

And more eloquent version of the code in ES6 with parenthesis around params and implicit return:

var ids = ['5632953c4e345e145fdf2df8','563295464e345e145fdf2df9']
var messages = ids.map((value, index, list) => `ID of ${index} element is ${value} `) // implicit return

7. Block-Scoped Constructs Let and Const

let

Up to ES5, JavaScript had only two types of scope, function scope and global scope. This caused a lot of frustration and unexpected behaviors for developers coming from other languages such as C, C++ or Java. JavaScript lacked block scope, meaning that a variable is only accessible within the block in which it’s defined. A block is everything inside an opening and closing curly bracket. Let’s take a look at the following example:

function foo() {
  var par = 1;
  if (par >= 0) {
    var bar = 2;
    console.log(par); // prints 1
    console.log(bar); // prints 2
  }
  console.log(par); // prints 1
  console.log(bar); // prints 2
}
foo();

const

const addresses the common need of developers to associate a mnemonic name with a given value such that the value can’t be changed (or in simpler terms, define a constant). For example, if you’re working with math formulas, you may need to create a Math object. Inside this object you want to associate the values of π and e with a mnemonic name. const allows you to achieve this goal. Using it you can create a constant that can be global or local to the function in which it is declared.

Constants defined with const follow the same scope rules as variables, but they can’t be redeclared. Constants also share a feature with variables declared using letin that they are block-scoped instead of function-scoped (and thus they’re not hoisted). In case you try to access a constant before it’s declared, you’ll receive a ReferenceError. If you try to assign a different value to a variable declared with const, you’ll receive a TypeError.

Please note, however, that const is not about immutability. As Mathias Bynens states in his blog post ES2015 const is not about immutabilityconst creates an immutable binding, but does not indicate that a value is immutable, as the following code demonstrates:

const foo = {};
foo.bar = 42;
console.log(foo.bar);
// → 42

If you want to make an object’s values truly immutable, use Object.freeze().

 

8. Classes in ES6

We can create class in ES6 using “class keyword. Classes creation and usage in ES5 was a pain in the rear, because there wasn’t a keyword class.

class Profile {   
   constructor(firstName, lastName = '') { // class constructor
      this.firstName = firstName;
      this.lastName = lastName;     
   }  
    
   getName() { // class method       
     console.log(`Name: ${this.firstName} ${this.lastName}`);    
   } 
}
let profileObj = new Profile('Kavisha', 'Talsania');
profileObj.getName(); // output: Name: Kavisha Talsania

I am not going to show you example of ES5 class creation, because there are many flavors.

 

9. Promises in ES6

Promises have been a controversial topic. There were a lot of promise implementations with slightly different syntax. q, bluebird, deferred.js, vow, avow, jquery deferred to name just a few. Others said we don’t need promises and can just use async, generators, callbacks, etc. Gladly, there’s a standard Promiseimplementation in ES6 now!

Let’s consider a rather trivial example of a delayed asynchronous execution with setTimeout():

setTimeout(function(){
  console.log('Yay!')
}, 1000)

We can re-write the code in ES6 with Promise:

var wait1000 =  new Promise(function(resolve, reject) {
  setTimeout(resolve, 1000)
}).then(function() {
  console.log('Yay!')
})

Or with ES6 arrow functions:

var wait1000 =  new Promise((resolve, reject)=> {
  setTimeout(resolve, 1000)
}).then(()=> {
  console.log('Yay!')
})

So far, we’ve increased the number of lines of code from three to five without any obvious benefit. That’s right. The benefit will come if we have more nested logic inside of the setTimeout() callback:

setTimeout(function(){
  console.log('Yay!')
  setTimeout(function(){
    console.log('Wheeyee!')
  }, 1000)
}, 1000)

Can be re-written with ES6 promises:

var wait1000 =  ()=> new Promise((resolve, reject)=> {setTimeout(resolve, 1000)})

wait1000()
  .then(function() {
    console.log('Yay!')
    return wait1000()
  })
  .then(function() {
    console.log('Wheeyee!')
  })

Still not convinced that Promises are better than regular callbacks? Me neither. I think once you got the idea of callbacks and wrap your head around them, then there’s no need for additional complexity of promises.

10. New Number Methods

ES6 added 2 new methods to the Number object:

  • Number.isInteger()
  • Number.isSafeInteger()

The Number.isInteger() Method

The Number.isInteger() method returns true if the argument is an integer.

Example

Number.isInteger(10);        // returns true
Number.isInteger(10.5);      // returns false

The Number.isSafeInteger() Method

A safe integer is an integer that can be exactly represented as a double precision number.

The Number.isSafeInteger() method returns true if the argument is a safe integer.

Example

Number.isSafeInteger(10);    // returns true
Number.isSafeInteger(12345678901234567890);  // returns false

Safe integers are all integers from -(253 – 1) to +(253 – 1).This is safe: 9007199254740991. This is not safe: 9007199254740992.

Comments

  1. Rahul bose

    Awsome . Thanks for writing this article. The links which you shared in comments was more about features in es6. Can you write along with new in ecmascript 2018