by finne on 19-03-2017

The next level JavaScript

march 2017

Since 2009 the 5th edition of JavaScript has been available. It is the current standard that is supported by all platforms. The 6th edition of JavaScript is called ECMAScript 2015 or ECMAScript 6 (ES6). This next level version was a long time coming, and delivers many improvements to the language. Future releases will be quicker: there is now a yearly release schedule. ES 2016 is already published, but not supported on all platforms.

ES6 is now supported in all modern browsers: Chrome, Firefox, Safari, Edge on the desktop and Chrome and Safari on mobile. Of these browsers and platform only Safari for desktop Mac is not automatically updated to the latest version (although it is free and you do get prompts for it). This means that users of all these platforms have good to perfect ES6 support (see kangax.github.io). Only IE (at 4% worldwide market share according to statcounter.com) is left out.

For older browser support you can transpile your JavaScript code using Babel. Although if you install a transpiler you might as well upgrade to TypeScript. TypeScript incorporates the latest (not yet natively supported) JavaScript language versions, and adds variable typing to JavaScript. It provides the most advanced version of JavaScript for developers today, although plain ES6 is not that far behind.

ES6 in practice

So you can write your JavaScript using ES6. What does this mean in practice? Here are the language features I immediately found worth using:

  • Strict mode: declare strict mode at the top of each JavaScript file so you use it everywhere. Strict mode is always enforced inside classes. It enables verbose errors instead of silent ones. It allows for faster JavaScript execution. Add this to the top of your files:
    // Enable whole-script strict mode.
    'use strict';

     

  • Declaring variables with const or let. This enforces you to write better code: const variables cannot be reassigned, so now your code can enforce this if you require it. Let and const variables are not hoisted to the top of the scope, so you are forced to declare a variable before you use it. ES5 var declarations did not enforce this. Also, global const and let variables are not added to the globel (window) object. They are stored separate, so the global window object is not 'contaminated'. Example: when a variable is never changed after assignment use a const:
    // ES5.
    var outcome = this.getStrength() - opponent_strength;
    if (outcome > 0) {
        this.tribute += outcome;
    }
    
    // ES6.
    const outcome = this.getStrength() - opponent_strength;
    if (outcome > 0) {
        this.tribute += outcome;
    }

     

  • Classes. The class declaration allows for a syntax that resembles classes in other programming languages, including extending classes, constructor functions, static methods, simple method declarations that are automatically added to the prototype. Example:
    // ES5.
    function Player(player_name) {
        this.name = player_name;
    
        this.prototype.addActiveBuilding = function (type) {
            this.active_buildings[type]++;
        };
    }
    
    // ES6.
    class Player {
        constructor(player_name) {
            this.name = player_name;
        }
    
        addActiveBuilding(type) {
            this.active_buildings[type]++;
        }
    }

     

  • Arrow functions. Apart from a shorter syntax (that I find sometimes a bit too short) the main attraction is that 'this' is scoped to the parent structure. Again this behaviour is more similar to other programming languages.
    element.addEventListener("click", () => {
          game = new Game();
    });
    

     

  • For... of loop. Because ES6 remains backwards compatible with ES5, the shortcomings of the for.. in loop cannot be fixed. So a new for loop was created: the for... of loop. Advantages: Looping with for... of loops over iteratable objects only. You will never loop over prototype keys. Also you can use break and continue. Again this brings the language more inline with other languages. You can loop over Arrays (defaults to Array.keys(), Maps (defaults to Maps.entries(), but not objects. For objects use Object.keys(myObject).
    for (const [key, value] of monuments) {
        for (const player of game.players) {
            if (player.monuments.get(key).active === true) {
                monuments.set(key, value);
                break;
            }
        }
    }

     

  • Objects in JavaScript are often used as associative arrays. The disadvantage of this is that an object inherits all kind of things from its prototype and also it can only use strings as keys. New in ES6 are Maps. a Map consists of key-value pairs where both can be arbitrary data. It has handy functions such as map.has(key) and properties such as map.size. Values can only be get and set with the getter and setter functions. Therefore Maps are not very friendly if you do a lot of mutations on your values, such as object.key++. If you use objects as associative arrays you should set the prototype to null to avoid the unneeded bagage that the normal Object prototype carries: Object.setPrototypeOf(myObject, null);
    let battle = new Map([
        ['conquest', false],
        ['tribute', false],
        ['barbarians', true],
        ['invasion', false]
    ]);
    if (battle.has('invasion')) {
        battle.set('tribute', true);
    }

     

  • Arrays that should only contain each value once can now be created using the Set construct. It is similar to a Map, but has no keys, and the values are unique.
     
  • String literals make string notation much more compact. You can also execute code inside a string literal, although you need to keep it brief so as not to loose the brevity advantage. Also, strings can now be declared on multiple lines:
    let html = `<div class="monument" data-type="monument" data-id="${key}">
         <img class="monument-img" src="img/monument-${key}.gif" title="${key}">
         </div>`;

     

  • Function parameter default values: functions can now have default values declared. Again this behaviour is more similar to other programming languages.
    activateNextStep(step, end = false) {
        if (end === false) {
            $('menu h4').removeClass('active');
        }
        this.step = step;
    }

     

  • Although modern browsers support ES6 'up to 100%', no browser supports the import and export statements. Module management is an unsolved problem in ES6 browser support. You will still need to declare each JavaScript file in your HTML head section. To take advantage of module management you have to use Babel or TypeScript.

 

ES6 for PHP programmers

For PHP programmers these language improvements make JavaScript ES6 behave more like PHP 7:

  • classes
  • arrow functions
  • for... of loops
  • maps / null prototyped objects
  • string literals
  • function parameter defaults

For more info I can recommend this book: http://exploringjs.com/es6.html

about the author

Finne Fortuin is Drupal development and deployment configuration expert. He also dabbles in JavaScript and offline (game) applications.

Finne