ES6 Revealed – A new world of Javascript

Only the elders of the software engineering world can still remember these dark times, when live/ecma/java – script (mocha, anyone?) was considered as no more than a clumsy, unpredictable, integrity lacking gimmick of a language, that served nothing more than form-validation and minor visual tool on almost-static web pages like this one.

These were the days when the server side was handling almost all there is to an application. Javascript was not reliable due to the fact that almost every browser at the time (IE, Firefox, Konqueror, Netscape and more) had a different implementation and API for processing javascript. Moreover, not all the language features were supported in all browsers, leading to initiatives like this one which most FEDs know, and of course, jquery, of which the first goal was to supply a cross-platform javascript API.

Things escalated quickly in 2005, when AJAX came to life, enabling programmers to create web-applications in which javascript played a major role of getting data and manipulating the DOM, instead of letting the server send more and more html upon page re-loads. Later, in 2008, when ecmascript 3.1 (renamed afterwards to ecmascript 5) was being developed, it gave developers more control and language features.

With the rise of both client-side MVC frameworks (Angular, Backbone, Ember, etc.) and of Node.js, javascript was no longer a name to be taken lightly. It became popular for most platforms (including server side, mobile applications) and is just getting better.

And yet, although it’s rising in popularity, javascript is still lacking on many fronts: It is a semi-functional , weakly-typed scripting language, thus enjoying features like high type flexibility, first order functions, high portability, rapid rate of development, and simplicity. But its support for OOP, moduling, scope logic (global variables in javascript are almost inevitable), type protection, and several other basic language features are still lacking.

To solve the above problems, many solutions have arisen: language supersets like:

Typescript that provides strong typing, alternatives-that-compile-to js like coffescript, Google’s dart, and even this cute one are trying to solve the above problems. Some of them were adopted by many companies and developers, but it seems that plain vanilla javascript is still the most used of them all.

Fortunately enough, the language keeps evolving. In 2015, the last in-product version of javascript, ecmascript 2015 (or JS6) was finalized and implemented into most major browsers (not IE!). This last standard is a huge update, even bigger than what JS5 was, and it introduces many language features that were painfully missing. Unlike in new versions of the stable, classic languages like c# and java, this update is really massive, some would say a total game-changer for the language .

Here is but an exhibition of the major new features now available:

JS is going OOP

Yes, you read correctly! OOP is based on data abstraction, inheritance, polymorphism and modularity, and now we can have all of them. class is now a reserved word, and can be used to define actual classes. As such, the usual technique of using protoypes and constructors as functions, is no longer needed. See for example, this code:

var ChessPiece = function (id, x, y) {
    this.id = id;
    this.move(x, y);
};
ChessPiece.prototype.move = function (x, y) {
    this.x = x;
    this.y = y;
};

is now simply translated into:

class ChessPiece {
    constructor (id, x, y) {
        this.id = id
        this.move(x, y)
    }
    move (x, y) {
        this.x = x
        this.y = y
    }
}

Inheritance, which is good for reuse, and the base for polymorphism is also present, with the extends keyword. This, along with Super that allows access to base class, and static that actually allows for static properties (which was painful to implement until now) allows us to do this:

class KarateDude {
  static dudesCount = 0;
  constructor(health,powerLevel){
    this.health = health;
    this.powerLevel = powerLevel;
    KarateDude.dudesCount++;
  }
  specialAttack(powerGauge){
    alert("doing my special move! it has " + powerGauge + " power!")
  }
  damageTaken(name,damage){
    this.health -=damage;
    alert(name + " is taking damage! now has " + this.health + " health left");
  }

}

class Ryu extends KarateDude{
  constructor(health,powerLevel,doesLikePunches){
    super(health,powerLevel);
    this.doesLikePunches = doesLikePunches;
  }
  specialAttack(powerGauge){
    super.specialAttack(powerGauge);
    alert(this.doesLikePunches? "Shoryuken!!!":"Hadouken!!!");
  }
}

class Ken extends KarateDude{
  constructor(health,powerLevel){
    super(health,powerLevel);
  }
  damageTaken(damage){
    super.damageTaken("Ken",damage)
    alert("aWWWWW!!");
  }
}

var ryu = new Ryu(100,3,true);
var ken = new Ken(100,5);
ryu.specialAttack(50);
ken.damageTaken(33);
alert("there are " + KarateDude.dudesCount + " dudes");

And that’s without breaking a sweat, so much more is at hand with just some motivation.

Scope logic is at hand!

So, we all know about the var keyword which allows defining variables, namely local variables, but those don’t really act like the usual variables we know from languages like c#. consider this code:

for(var i = 0; i<n; i++){
	// whatever...
}
console.log(i);

Had we been in C++, Java, C# etc., the result should have been a logical compilation error. the variable i isn’t declared in the current scope of the log. but in javascript… it works, because variables are tied to the nearest function scope.

Next comes let, which allows you to have variables tied only to the last block, so they affect only where they should and make this mess more comprehensible.

One other cute fact, is that let variables do not hoist, which makes weird code like this:

console.log(x); // undefined, x is hoisted, does not throw!
var x;

throw an error, as you would expect

console.log(x); // error
let x;

Basic support for advanced data structures

Many known algorithms require different sorts of destined data structures, such as queues, heaps, sets, and more. Until now, javascript had supported only standard arrays and “objects” that also behaved as maps. From now on, we can have a little more official and versatile data structures: sets and maps.

Set is a data structure that allows keeping a set of unique items.

let s = new Set();
s.add("roastbeef").add("bread").add("roastbeef");
s.size === 2;

Maps are entries of key/value, that are implemented as a hash table, and are different from traditional objects by both the API and the fact that they do not contain any members aside from the ones added by code. (Objects have many properties inherited by their prototype, and that had always been a setback while trying to iterate over all object fields).

let s = "something"
let m = new Map();
m.set("hello", 42);
m.set(s, 34);
m.get(s) === 34;
m.size === 2;
for (let [ key, val ] of m.entries())
    console.log(key + " = " + val);

yield-return anyone?

Another major change is the addition of generators. These are special functions that can stop their own execution, and when called again, start from where they stopped. This enables cooperation of code, and opens a new world of possibilities. One of them, is implementing the yield-return pattern from C#:

function* range (start, end, step) { // see the *? that’s how a generator is declared
    while (start < end) {
        yield start; // the generator will return with the value of start.
        start += step; // this is where execution will continue next time range is called
    }
}

for (let i of range(0, 10, 2)) {
    console.log(i); // 0, 2, 4, 6, 8
}

More about the coolness of generators is available here: https://davidwalsh.name/es6-generators

Some more delicious tweaks

Arrow functions

let isString =  e => typeof(e) === 'string';
arr.map(e => e.id); // lambda anyone?
let doSomething = (a,b,c) => {
	// whatever...
}

New Array functions

[ 1, 3, 4, 2 ].find(x => x > 3); // 4
"no" + "!".repeat(5); // no!!!!!

Iterators

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 > 1000)
        break;
    console.log(n);
}

So, should we start using javascript 6?

Yes! totally! do it now!!!

Alright, alright, let’s get realistic here. The decision to start using JS6 is not an easy one. On one hand, there is a whole world of new possibilities , so many features the language was lacking and ways to make the code more concise and readable. But on the other hand, there are numerous drawbacks:

Browser compatibility

As stated before, not all browser vendors implement new features at the same pace. While some browsers (Chrome and Opera’s last versions) already support all JS6 features, other browsers like Edge 12, Safari 9, and IE (god save us) give only partial support or none at all.

If your app is targeted only at users who are likely to adopt cutting edge technological progress, then that’s not a problem. But if you want to enable legacy users to use your app, you will need a workaround.

Luckily, projects like babel and traceur are able to transpile es6 code into es5, and thus let you code with all new features, and still, run code that works on all browsers.

Full compatibility list

Learning curve

Since many features (generators, classes, module system – which was not discussed here) give the programmer many new capabilities and are complex mechanisms by themselves, they will require a javascript team to learn and get used to them. This might impact the pace of development until all new features are mastered.

Code structure is very different

As stated before, the introduction of classes makes the declaration of data models very different. The usage of let and const (not introduced in this article) makes code practices different than before. Legacy code is still stable, but in order to really write ES6, using all features combined correctly, the way code is written will change.

An example of this can be taken from the Angular 2 site, of writing a small app in both ES5 https://angular.io/resources/live-examples/quickstart/js/plnkr.html – es5
https://angular.io/resources/live-examples/quickstart/ts/plnkr.html – es6

(yes, it’s typescript and not es6, but it’s very similar in this part, and it passes the argument)

While all the above is correct, it may still be a good idea to start the process of migration. Many companies have already started to move, and many new frameworks (like angular 2, see above) are more suited to be used with JS6 than traditional javascript. Staying behind may be comfortable for the moment, but it has the cost of unused abilities, being one step behind the rest of the world, and may result in the inability to adopt new technologies and develop world-class code.

Leave a comment