Javascript of the Future

The history of Javascript, formally known as ECMAScript and originally Mocha, is a strange one. Originally developed by Brendan Eich at Netscape in ten days with the intention of creating a scripting language for the Web which could be picked up by new programmers, it has been praised and maligned in every corner of the Internet, by the same people in equal measure. The little language that could, or could at least try its hardest, has now spread past the browser to runtime environments like Node.js, game engines like Unity and “hybrid” mobile apps. This ubiquity is forcing the language to grow in scope and style dramatically.

The next, better equipped, better looking version, ECMAScript 6, is finally here. And in light of its upcoming integration with Sprockets and its final specification being released, now is a good time to get familiar with it.

Sugar coating

Much has been made about the influence CoffeeScript has had on ES6, and the language is certainly starting to look more like its sister. New syntactic sugar for Object constructors, ‘fat arrow’ functions and destructured assignment go a long way towards making Javascript feel fresh.

There are better resources for actually learning ES6, but here’s a quick look at what New Javascript looks like.

// A new Class syntax.
class Person {
  // Destructured object arguments, with defaults
  constructor({ job = 'Unemployed', age = random(1, 100) } = {}) {}

  // Default arguments  speak(message = 'Hello') {
    // Template strings have their own `special quotes`
    console.log(`${this.name} said ${message}`);
  }}

// Fat arrow functions maintain context, just like Coffeescript
doubler = (num) => { num * 2 };

// Constants cannot be redefined
const x = 1;

// Lets have block specific variable scope
let y = 2;

There is a new native module loader syntax which manages to fit in with the CommonJS spec used by Node and Browserify, and the RequireJS spec popular elsewhere. The following are equivalent statements.

// CommonJS
var t = require('tape');
var inherits = require('util').inherits;

// ES6import * as t from 'tape';
import { inherits } from 'util';

More excitingly, but less visibly, ES6 has borrowed more liberally from CoffeeScript’s inspiration, Ruby, and the concurrency craving Go. With new features like Proxies, Promises and extended Prototype under its skin, Javascript is becoming a more mature scripting language, without sacrificing the ultra object orientation and transparency that makes it unique. And with the accelerated release schedule ECMAScript is adopting, we should expect it to quickly adopt even more from the ‘programmer happy’ scripting languages out there, with async/await functions coming in ES7 and Macros proposed for ES8, allowing the creation of custom DSLs à la sweet.js.

Metaprogramming

Metaprogramming means writing code which is introspective and can modify itself, or other programs. Javascript historically has limited support for advanced metaprogramming as developers have been bound to using the high level APIs of Objects, but that has changed with the introduction of Proxies.

Proxies utilise ‘traps’ to intercept language level object events. There are 14 traps available, including get, set and setPrototypeOf and each can be used to observe or even replace a native manipulation of an object. It allows deeper access to an object’s natural functionality than getters or setters, function methods like Function#call and Function#apply or Object methods likeObject#keys have in the past. Although their compatibility is limited at the moment, their potential going forward is great.

In Ruby method_missing can be defined on an object, and any subsequent calls which do not match existing methods will be run through it. It allows Ruby developers to create dynamic functionality like Rails’ find_by_* methods. Proxies provide a much lower level ability to observe and intercept objects, but defining a get trap could lead to similar functionality in JS objects.

var methodMissing = function(target, handler){
  return new Proxy(target, {
    // Intercept 'get' actions, like input.value
    get(ref, prop){
      let skip = function(){
        // The Reflect API provides access to native functionality,
        // so we can fallback if necessary.
        return Reflect.get(target, prop);
      }

      // Fallback if the property already exists.
      if(target.hasOwnProperty(prop))
        return skip();

      // Pass the functionality to the handler defined.
      return handler.call(this, prop, target, skip);
    }
  });
}

Of course, this could be used for a wide variety of interactions. For example we could proxy Backbone Collections to ape functionality similar to ActiveRecord’s dynamic finder methods.

library.findByName('Into Thin Air');
library.findByNameAndAuthor('Supergods', 'Grant Morrison');

Directly proxying function calls on an object to HTTP requests to an external API could make building RESTful API wrappers simple, and futureproof.

facebook.user({ id: 12345 }, (err, user) => {  });
twitter.tweet({ message: 'Test message' }, (err, response) => {  });

Promises and the future

Those of you familiar with Node.js or libraries like Bluebird or Q will be aware of Promises, and how useful they are for avoiding the callback hell which can easily plague asynchronous Javascript with the best of intentions. The concept behind Promises is that instead of an asynchronous function accepting a callback – a common Javascript paradigm – it returns an object which will later be fulfilled.

var p = $.getJSON('api.dev.battle.net/whatever')
  .then((err, response) => { console.log(response.results); })
  .error(handleErrors);

Splitting your asynchronous code up like this allows for chainability, code organisation and consolidated error handling.

Generators

Generators are a new type of function which yield a value, returning it and temporarily stopping function execution. It won’t start up again until the next value is requested. The following shows an example fibonacci sequence generator which could run infinitely, but will only run as many times as is needed.

var fibonacci = function*(){
  var last = 0
    , current = 1;

  while(true){
    let old = last;
    last = current;
    current += old;

    // Yield halts the function and returns a value.
    yield current;
  }}

// Generators can be iterated through with the new 'of' syntax
for(var num of fibonacci()){
  if(num >= 1000) break;
  console.log(num);
}

Using it now

You can try the language online with the Babel REPL. The language isn’t production ready by itself. Compatiblity still isn’t there and it won’t be for a while.

However, I’ve been writing ECMAScript 6 for a while now and transpiling it into ES5 using, originally, Traceur and now Babel.js. They translate as much of the new language features and syntax as they can into a version of Javascript with high compatibility, which can be used in existing environments. New features like Proxies which weren’t possible before, and therefore cannot be transpiled, are available in new releases of Firefox and, somewhat surprisingly, Microsoft’s Edge browser.

Naturally, as time goes on, compatibility in current browsers and runtimes will increase, but for the time being these are a good way to get writing ES6 today. I’ve been using Gulp tasks similar to this to translate my source folder to an ES5 folder, which I use as the index of my Node projects.

Node tip: Ignore the build folder in Git, add a “prepublish” script to your package.json to run the Gulp task.

Going forward

Perhaps the most interesting aspect of ES6, and the greatest testimony to the Javascript community at large, is that the features on the surface of this update aren’t that exciting. A lot of this functionality became part of the spec and got introduced early by eager developers, or has been ‘pulled into master’ after exploding in the Javascript community. In a way Javascript often feels like ‘build-a-language’, as the community is so vibrant and passionate about extending the language as they see fit.

For all intents and purposes, JavaScript has merged CoffeeScript into master. I call that a victory for making things and trying them out.

– Reginald Braithwaite

The greatest parts of ES6 are the parts you miss at first glance. The combination of Generators and Promises are changing everything. There are already complete libraries like Co for manageable flow control built with this combination. It is the cornerstone of async/await functionality in ES7 and essential to the next few official releases.

// One day.
var users = async function(){
  var response = await request('/users');
  return response.data;
}

The future for Javascript is unclear, but the language is getting stronger every day. Should the language continue to provide building blocks to its enthusiastic developers and then standarise their creations natively, the future of Javascript will continue to be up to the people using it.

About the Author

Richard Foster

Lead Software Engineer at Made Tech. Making something from nothing for fun and profit. Actually likes Javascript.

Avatar for Richard Foster

We are hiring! Find out more about a career at Made Tech.

Download a copy of our new book

Legacy technology is one of the biggest threats to public sector organisations.
Whether you’ve started your journey already or don’t know where to begin, this 160-page book has been written to guide you to define and implement the right approach for your organisation.