Replace CoffeeScript with ES6

Blake Williams

I’ve been looking into ES6, the next version of JavaScript, and finally got a chance to use it on a project. In the brief amount of time I was able to use it I’ve found that it solves a lot of the problems that CoffeeScript is trying to solve without drastic syntax changes.

Using ES6 Today

We can start using ES6 today through the 6to5 project which transpiles our ES6 code into ES5. 6to5 supports a plethora of build tools including Broccoli, Grunt, Gulp, and Sprockets. I’ve had a lot of success using sprockets-es6, and Sprockets 4.x will have out-of-the-box support for 6to5.

If you’re using Vim you’ll want to associate the .es6 file extension with JavaScript by putting the following code into your .vimrc.

autocmd BufRead,BufNewFile *.es6 setfiletype javascript

You can also use the 6to5 REPL to try out ES6 in your browser.

Classes

Both CoffeeScript and ES6 have class support. Let’s look at a CoffeeScript class compared to the ES6 equivalent.

CoffeeScript allows us to take advantage of setting instance variables from the parameters, string interpolation, and calling functions without parentheses:

class Person
  constructor: (@firstName, @lastName) ->

  name: ->
    "#{@first_name} #{@last_name}"

  setName: (name) ->
    names = name.split " "

    @firstName = names[0]
    @lastName = names[1]

blake = new Person "Blake", "Williams"
blake.setName("Blake Anderson")
console.log blake.name()

With ES6 we can take advantage of classes, getters, and setters:

class Person {
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }

  get name() {
    return this.firstName + " " + this.lastName;
  }

  set name(name) {
    var names = name.split(" ");

    this.firstName = names[0];
    this.lastName = names[1];
  }
}

var blake = new Person("Blake", "Williams");
blake.name = "Blake Anderson"
console.log(blake.name);

If you’ve used any library or framework that provides classes in JavaScript you’ll notice the ES6 syntax has some minor differences:

  • There is no semicolon after the function name
  • The function keyword is omitted
  • There are no commas after each definition

We’re also taking advantage of getters and setters which allow us to treat the name function like a property.

Interpolation

I’ve often wished for a more powerful string syntax in JavaScript. Fortunately ES6 introduces template strings. Let’s compare CoffeeScript strings, JavaScript strings, and template strings to see what each is capable of.

CoffeeScript:

"CoffeeScript allows multi-line strings
with
interpolation like 1 + 1 = #{1 + 1}
"

JavaScript strings:

"JavaScript strings can only span a single line " +
  "and interpolation isn't possible"

ES6 template strings:

`Template strings allow strings to span
multiple lines and allow interpolation like 1 + 1 = ${1 + 1}
`

We can take advantage of template strings in our previous example by changing our name getter to the following:

get name() {
  return `${this.firstName} ${this.lastName}`;
}

This feels much cleaner than the string concatenation we were doing before and gets us closer to the CoffeeScript example.

Fat Arrows

Another feature that made CoffeeScript so appealing also makes an appearance in ES6: fat arrows. Fat arrows allow us to bind a function to the current value of this. First, let’s take a look at how we can handle this without a fat arrow.

With ES5 we have to keep a reference to the current value of this when defining the function:

var self = this;

$("button").on("click", function() {
  // do something with self
});

CoffeeScript fat arrows can omit arguments and parentheses entirely:

$("button").on "click", =>
  # do something with this

ES6 fat arrows require the parentheses with or without arguments:

$("button").on("click", () => {
  // do something with this
});

Other features

ES6 has a few other features worth worth noting in passing.

Default arguments

CoffeeScript:

hello = (name = "guest") ->
  alert(name)

ES6:

var hello = function(name = "guest") {
  alert(name);
}

Splats

Variadic functions, which CoffeeScript calls splats, allow you to collect additional arguments passed to your function as an array. ES6 refers to them as rest arguments.

CoffeeScript:

awards = (first, second, others...) ->
  gold = first
  silver = second
  honorable_mention = others

ES6:

var awards = function(first, second, ...others) {
  var gold = first;
  var silver = second;
  var honorableMention = others;
}

Destructuring

Destructuring allows you to pattern match against arrays and objects to extract specific values.

CoffeeScript:

[first, _, last] = [1, 2, 3]

ES6:

var [first, , last] = [1, 2, 3]

We can use destructuring in the name setter we defined earlier to make our code more concise:

set name(name) {
  [this.firstName, this.lastName] = name.split(" ");
}

Wrapping Up

ES6 transpilers are actively being developed and are catching up to CoffeeScript in functionality. This post only covered a handful of the features that ES6 is bringing to JavaScript.

On your next project set CoffeeScript aside and give ES6 a shot!