Ecmascript 6

ECMAScript 6 aka Harmony

Hi Guys, this is a blog where I will be talking about ES6 codenamed “Harmony”. Starting with a short history on the growth of ECMAScript world, leading to listing the features/changes implemented in ECMAScript 6 and explaining few of those prominent features comparing it with ECMAScript 5. Lastly, I will give a brief note on the future of ECMAScript 6. To start with I will assume the readers have basic knowledge of core JavaScript.

Introduction

The JavaScript core language features are defined in a standard called ECMA-262. The language defined in this standard is called ECMAScript. When we consider browsers, they add more capabilities to the core of the language through their own additional native methods and objects.

There was not much change in JavaScript since the third edition of ECMA-262 was published in 1999. It was in 2007, the committee that was responsible decided to go big and launched ECMAScript 4, which was massive in scope. ES4 included new syntax, modules, classes, optional type notations etc.

After the launch of ES4, a group of leaders from Yahoo, Microsoft and Google came up with an alternate proposal for the next version of ECMAScript which they initially called ECMAScript 3.1.

Note: The “3.1” was to show that this was an incremental change to the existing standard. In other words, ES3.1 was introduced after ES4.

This unfortunately was not a great success because ES3.1 and ES4 had two very different or ‘Inharmonious’ perspective on the language growth.

In 2008, Brendan Eich, the creator of JavaScript announced to focus on standardizing ES3.1. Next, the committee focussed on getting together the best parts of ES3.1 and ES4 into a harmonious growth, avoiding the two separate branches mentioned earlier. And, that is how ECMAScript 6 was born. Also, the nickname “Harmony” came into existence. ES6 reached its final status in 2014.

Compatibilty

Many JavaScript environments such as web browsers and Node.js are actively working on implementing ECMAScript 6. Here is an image showing the compatibility table of ES6 by kangax. Here is the link for the same.

Kangax

Using ES 6 in Browsers

In Chrome, most of the ES6 features are hidden behind a flag called "Experimental JavaScript features".

Visit chrome://flags/#enable-javascript-harmony, enable this flag, restart Chrome and you will get many new features.

Arrows are complete in V8 at the point of this blog writing, and already ship without flag. Chrome 45 (soon to be in beta) will pick them up.

Since arrow functions are a syntax change, it is not possible to support this syntax without changing the way how JavaScript is parsed. If you like developing in ES6, then you could write ES6 code and use an ES6-to-ES5 compiler to generate JavaScript code that is compatible with all existing(modern) browsers.

New Features

  • arrows
  • classes
  • enhanced object literals
  • template strings
  • destructuring
  • default + rest + spread
  • let + const
  • iterators + for..of
  • generators
  • unicode
  • modules
  • module loaders
  • map + set + weakmap + weakset
  • proxies
  • symbols
  • subclassable built-ins
  • promises
  • math + number + string + array + object APIs
  • binary and octal literals
  • reflect api
  • tail calls

I will be demonstrating only a few, on how the features have changed from ES 5 to ES 6 syntax wise.

Arrow Functions

Arrows are a function shorthand using the => syntax. Unlike functions, arrows share the same lexical this as their surrounding code.

Expression bodies

ECMAScript 5

evens = [2,4,6,8]
odds  = evens.map(function (v) { return v + 1; })
// result : [3, 5, 7, 9] 

ECMAScript 6

evens = [2,4,6,8]
odds  = evens.map(v => v + 1)
// result : [3, 5, 7, 9]

Statement bodies

ECMAScript 5

nums = [1,2,13,44,32,45,77,120,96,10]
fives = []
nums.forEach(function (v) {
   if (v % 5 === 0)
       fives.push(v);
});

fives
// result : [45, 120, 10]

ECMAScript 6

nums = [1,2,13,44,32,45,77,120,96,10]
fives = []
nums.forEach(v => {
   if (v % 5 === 0)
       fives.push(v)
})

fives
// result : [45, 120, 10]

Object Enhancements

ECMAScript 5

var color = "black";
var size = 4;

var phone = {color:color, size:size};

//phone.color => black
//phone.size => 4

ECMAScript 6

var color = "black";
var size = 4;
function buy() {
    console.log("pay the amount");
}

var phone = {color, size, buy};

//phone.color => black
//phone.size => 4
//phone.buy() => pay the amount

In ES 6, If we declare the property the exact same name as something, it will treat it just as you did name:property. As you can see the example it even works well with a function.

Another cool thing is instead of actually using the function keyword, we can directly declare the function on an object like so(without using the function keyword),

var color = "black";
var size = 4;

var phone = {
    color,
    size,
    buy() {
        console.log("pay the amount");
    }
};

//phone.color => black
//phone.size => 4
//phone.buy() => pay the amount

Whereas in ES 5 it would have been,

var phone = {
    color,
    size,
    buy: function() {
        console.log("pay the amount");
    }
};

String Templates

If you have worked with JavaScript you have most likely concatenated strings and variables using +. Something like this,

ECMAScript 5

var first = "Java is to JavaScript";
var final = first + ", what Car is to Carpet"

//result => Java is to JavaScript, what Car is to Carpet

ES6 on the other hand allows you to place the variables inside of your string. For example, the above code can be rewritten as.

ECMAScript 6

var first = "Java is to JavaScript";
var final = `${first}, what Car is to Carpet`

//result => Java is to JavaScript, what Car is to Carpet

The key differentiator here is, it respects white space across multiple lines.

var first = "Java is to JavaScript";
var final = `
${first},
        what
    Car
is
        to
        Carpet`;

console.log(final);

//result => 
Java is to JavaScript,
        what
    Car
is
        to
        Carpet

You can also do expressions inside the braces like so,

var a = 1;
var b = 9;
var sum = `${ a } + ${ b } = ${ a + b }`

sum

//result => 1 + 9 = 10

Lastly, an introduction about tagging the string templates.

var mood = `Its ${new Date().getHours()}, im sleepy`

mood

result => Its *whatever time*, im sleepy

Let me tell you an awesome thing. We can actually calculate and parse the value of the variable. Also, we can change the string or a part of the string based on the value.

So lets keep the value to be displayed as an empty string.

function parse(strings, ...values){
    if(values[0] < 20) {
        values[1] = "awake";
    }
    else {
        values[1] = "sleepy";
    }

    return `${strings[0]}${values[0]}${strings[1]}${values[1]}`
}

var mood = parse`Its ${new Date().getHours()}, im ${""}`

mood

result => if the time is below 8PM, it will be awake otherwise sleepy.

New Built-In Methods

In ES 6, there are many Built-In methods introduced. I will introduce each with an example in details.

Finding Array Element

In ES 5, finding an element in an array was considerably complex, like so

[ 1, 3, 4, 2 ].filter(function (x) { return x > 3; })[0];

// result => 4

Now in ES 6 there is a Built-In function named find to do the same task in a cleaner way.

[ 1, 3, 4, 2 ].find(x => x > 3);

// result => 4

Repeating Strings

In ES 5, repeating a string was done using the Array datatype.

Array(3 + 1).join("word");

// result => wordwordword

In ES 6, there is a Built-In function to repeat a string.

"word".repeat(3)

// result => wordwordword

Search for a sub-string

In ES 5, indexOf method was used to search for a substring in a given string.

"hello".indexOf("ello") === 1;    // true
"hello".indexOf("hell") === (4 - "hell".length); // true
"hello".indexOf("ell") !== -1;    // true
"hello".indexOf("ell", 1) !== -1; // true
"hello".indexOf("ell", 2) !== -1; // false

In ES 6, there are few other new functions such as startsWith, endsWith, includes introduced for the same task. These can be used as shown below.

"hello".startsWith("ello", 1) // true
"hello".endsWith("hell", 4)   // true
"hello".includes("ell")       // true
"hello".includes("ell", 1)    // true
"hello".includes("ell", 2)    // false

Number Type Checking

In ES 5, a number can be checked as non-numbers(NaN) or finite number by doing so.

var isNaN = function (n) {
    return n !== n;
};
var isFinite = function (v) {
    return (typeof v === "number" && !isNaN(v) && v !== Infinity && v !== -Infinity);
};
isNaN(42) === false;
isNaN(NaN) === true;

isFinite(Infinity) === false;
isFinite(-Infinity) === false;
isFinite(NaN) === false;
isFinite(123) === true;

In ES 6, the same can be achieved using the Built-In isNaN and isFinite functions.

Number.isNaN(42) === false
Number.isNaN(NaN) === true

Number.isFinite(Infinity) === false
Number.isFinite(-Infinity) === false
Number.isFinite(NaN) === false
Number.isFinite(123) === true

Number Type Checking

In ES 5, to check whether a given number is in the safe range or not(where all numbers, including integer numbers, are technically floating point number), we need to actually write a seperate function as demonstrated.

function isSafeInteger (n) {
    return (
           typeof n === 'number'
        && Math.round(n) === n
        && -(Math.pow(2, 53) - 1) <= n
        && n <= (Math.pow(2, 53) - 1)
    );
}
isSafeInteger(42) === true;
isSafeInteger(9007199254740992) === false;

In ES 6, thankfully there is a Built-In function for the same called isSafeInteger and can be used like so

Number.isSafeInteger(42) === true
Number.isSafeInteger(9007199254740992) === false

Truncating a Number

In ES 5, we need a create a seperate function to truncate a number which can be written as.

function mathTrunc (x) {
    return (x < 0 ? Math.ceil(x) : Math.floor(x));
}
console.log(mathTrunc(42.7)) // 42
console.log(mathTrunc( 0.1)) // 0
console.log(mathTrunc(-0.1)) // -0

Whereas in ES 6 there is a function named Math.trunc which does the same thing.

console.log(Math.trunc(42.7)) // 42
console.log(Math.trunc( 0.1)) // 0
console.log(Math.trunc(-0.1)) // -0

Promises

Promises are used in many currently existing JavaScript library.Promises are a library for asynchronous programming. Promises are a first class representation of a value that may be made available in the future

Usage of Promises in ES 5.

function msgAfterTimeout (msg, who, timeout, onDone) {
    setTimeout(function () {
        onDone(msg + " Hello " + who + "!");
    }, timeout);
}
msgAfterTimeout("", "Foo", 100, function (msg) {
    msgAfterTimeout(msg, "Bar", 200, function (msg) {
        console.log("done after 300ms:" + msg);
    });
});

Usage of Promises in ES 6.

function msgAfterTimeout (msg, who, timeout) {
    return new Promise((resolve, reject) => {
        setTimeout(() => resolve(`${msg} Hello ${who}!`), timeout)
    })
}
msgAfterTimeout("", "Foo", 100).then((msg) =>
    msgAfterTimeout(msg, "Bar", 200)
).then((msg) => {
    console.log(`done after 300ms:${msg}`)
})

Tail Calls

A tail call happens when a function F makes a function call as its final action. At that point, F will do absolutely no more work. It passes the ball to whatever function is being called and vanishes from the game. This is notable because it opens up the possibility of tail call optimization. Instead of creating a new stack frame for the function call, we can simply reuse F’s stack frame. Thereby, saving stack space and avoiding the work involved in setting up a new frame.

Calls in tail-position are guaranteed to not grow the stack unboundedly. Makes recursive algorithms safe in the face of unbounded inputs.

The following code will give an Internal error too much recursion

function factorial(n, acc = 1) {
    'use strict';
    if (n <= 1) return acc;
    return factorial(n - 1, n * acc);
}

// Stack overflow in most implementations today,
// but safe on arbitrary inputs in ES6
factorial(100000)

// result => InternalError: too much recursion 
// result if factorial(10) => 3628800

Future of ECMAScript 6

ES6 is gaining a lot of momentum in the ecosystem. Chrome and io.js have already incorporated some of its features.

But, what’s worth pointing out is this momentum has been largely enabled by transpilation rather than the actual support. Good tools have emerged to enable transpiling and polyfilling, and browsers have over time added proper debugging and error reporting support for them.

There’s still a substantial amount of work left to make sure an easier adoption of new language syntax. Also, APIs become more friction-less to the beginners.

But, one thing is for certain. We must embrace the moving target.

Leave a Reply

Your email address will not be published. Required fields are marked *