Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Future JavaScript, today: Google's Traceur

DZone's Guide to

Future JavaScript, today: Google's Traceur

· Web Dev Zone ·
Free Resource

Learn how error monitoring with Sentry closes the gap between the product team and your customers. With Sentry, you can focus on what you do best: building and scaling software that makes your users’ lives better.

ECMAScript is a language working as an umbrella for JavaScript, Internet Explorer's JScript and Flash ActionScript. Innovation in browsers today is coming from their support for HTML5 and CSS3 features, but also from the incorporation of new versions of ECMAScript.

All browsers support ECMAScript 3, which came out in 1999 and practically defines JavaScript as we know it today. ECMAScript 5 (originally 3.1) is in current adoption and supported in browsers such as Internet Explorer 9, Firefox 4, Safari 5 and Chrome. It provides first class object properties with metadata definition, allowing for example to specify if one of them can be deleted or modified at all.

We can expect that in the next one or two years we will be able to use ECMAScript 5 features as the base JavaScript language, with an eye to older browsers.

To take a look even more into the future, we should target ECMAScript Harmony (no version number for now), which will be the next specification. Its development is in flux, but many features are so interesting that trying them out is worth the hassle.

But how to experiment with ECMAScript Harmony? The tool we'll explore in this article is Google's Traceur, a compiler that converts on the fly future JavaScript in current day one.

Mechanics

While CoffeeScript enhances current day JavaScript, providing a different language with the same semantics, Traceur works on future features. It lets you tryout features from ECMAScript Harmony, and still compiles to JavaScript in order to run into all browsers.

The alternatives are to execute the compilation step offline, or even in the browser; since the compiler is written in JavaScript itself, it can run in pretty much every environment.

All you have to do to use Traceur is to write your code into a <script type="text/traceur"> tag, and to include another <script> for the compiler hosted on a public server.
Performance is not great with JIT compilation, so be careful before writing real code with this tool.

Examples

Let's dive into the features that ECMAScript Harmony will offer (if they are confirmed in the final version of the specification) and that Traceur lets you try out today.

I've taken some of the examples from Traceur's wiki and shortened them as much as possible for your convenience, then collapse them in a single file so that you can run it in your browser. Loading this .html file with Firebug or Chrome's console open will suffice to see Traceur and Harmony in action, even when loading from the local filesystem.

<!DOCTYPE html>
<html>
  <head>
    <title>Hello, World!</title>
    <script src="http://traceur-compiler.googlecode.com/svn/branches/v0.10/src/traceur.js"
        type="text/javascript"></script>
    <script src="http://traceur-compiler.googlecode.com/svn/branches/v0.10/src/bootstrap.js"
        type="text/javascript"></script>
  </head>
  <body>
    <script type="text/traceur">
    /**
     * Classes, finally.
     * http://wiki.ecmascript.org/doku.php?id=strawman:obj_initialiser_class_abstraction
     */
    class Greeter {
        // the constructor
        new(message) {
          this.message = message;
        }

        greet() {
          let element = document.querySelector('#message');
          element.innerHTML = this.message;
        }
    };
    
    let greeter = new Greeter('Hello, world!');
    greeter.greet();

    /**
     * let statements provide a block scope for variables, smaller than the
     * function or global scopes we often use.
     * Inside the block, variables shadow the outer scoped ones (if they exist)
     * with the same name.
     */
    let ordinal = '3rd';
    for (let i=4; i<10; i++) {
        let ordinal = i + 'th';
        // ...
    }
    console.log(ordinal); // 3rd
    

    /**
     * Traits are a mechanism for code reuse which lets you share method 
     * definitions between classes. They're also included in future versions 
     * of PHP and present in Ruby with the name of mixins.
     */
    trait ComparableTrait {
        // abstract methods: must be defined by the including class
        requires lessThan;
        requires equals;

        function lessThanOrEquals(other) {
            return this.lessThan(other) || this.equals(other);
        }
    }

    class Interval {
        // you can include multiple traits
        mixin ComparableTrait;

        new(min, max) {
            this.start = min;
            this.end = max;
            this.size = max - min - 1;
        }
        function lessThan(ival) {
            return this.end <= ival.start;
        }
        function equals(ival) {
            return this.start == ival.start && this.end == ival.end;
        }
    }

    var i1 = new Interval(0, 5);
    var i2 = new Interval(7, 12);
    // both methods from the class and its traits are available
    console.log(i1 + ' <= ' + i2 + ': ' + i1.lessThanOrEquals(i2));        // true
    console.log(i1 + ' <= ' + i1 + ': ' + i1.lessThanOrEquals(i1)); // true
    console.log(i2 + ' <= ' + i1 + ': ' + i2.lessThanOrEquals(i1)); // false

    /**
     * Modules as first-class citizens would be very handy in integrating
     * different libraries, vendor code with our own...
     * NOT YET IMPLEMENTED in Traceur 0.10: you will get an exception 
     * if you uncomment this.
    module Profile {
        export var firstName = 'David';
        export var lastName = 'Belle';
        export var year = 1973;
    }

    module ProfileView {
        import Profile.{firstName, lastName, year};

        function setHeader(element) {
            element.textContent = firstName + ' ' + lastName;
        }
    }
    ProfileView.setHeader(document.querySelector('#name'));
     */

    /**
     * Destructuring allows multiple initialization based on pattern matching,
     * similarly to PHP list(). It's however more powerful being also recursive.
     */
    var [a, [b], c, d] = ['hello', [', ', 'junk'], ['world']];
    console.log(a + b + c); // hello, world

    /**
     * Default parameters do not need further explanation.
     */
    function hello(who='world') {
        console.log('Hello! Hello, ' + who);
    }
    hello(); // Hello! Hello, world
    hello('Giorgio'); // Hello! Hello, Giorgio
    /**
     * The interesting thing is that the default value may be any expression,
     * not just a constant.
     */
    function name() { return 'Giorgio' }
    function goodbye(who = name()) {
        console.log('Goodbye ' + who);
    }
    goodbye(); // Goodbye, Giorgio
    </script>
    <h1 id="message"></h1>
    <div id="name"></div>
  </body>
</html>

There are a few more features to explore, like support for iterators or yet another way to provide parameters to functions (in a variable number); however, I feel these are the ones that will have the most impact.

The ultimate goal of Traceur is to allow people to try out the new features and participate to the specification process, so that when the next ECMAScript comes out it has already been put under scrutiny by a multitude of developers: from iteration comes perfection. Happy hacking with Harmony!

What’s the best way to boost the efficiency of your product team and ship with confidence? Check out this ebook to learn how Sentry's real-time error monitoring helps developers stay in their workflow to fix bugs before the user even knows there’s a problem.

Topics:

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}