Skip to content

Instantly share code, notes, and snippets.

@conoremclaughlin
Forked from benjie/README.md
Last active September 4, 2015 13:21
Show Gist options
  • Select an option

  • Save conoremclaughlin/86442f0c7cbe955a9c9e to your computer and use it in GitHub Desktop.

Select an option

Save conoremclaughlin/86442f0c7cbe955a9c9e to your computer and use it in GitHub Desktop.
Long Live CoffeeScript and Long Live ES6

ES6 is cool, but CoffeeScript still does it better

Clearly ES6 is a huge improvement over ES5, and tools like 6to5 allow us to use these cool features now. I was reading [Replace CoffeeScript with ES6][replace coffeescript] by Blake Williams and thought it was a great summary of how ES6 solves many of the same problems that CoffeeScript solves; however I'd like to comment on a few of Blake's points.

Classes

Classes in ES6 (like many features in ES6) are very similar to the CoffeeScript equivalent. To support browsers that are not fully ES5 compliant (e.g. IE8-), however, we still can't really use getters/setters, so ignoring these the comparison is:

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

  name: ->
    "#{@firstName} #{@lastName}"

  setName: (name) ->
    [@firstName, @lastName] = name.split " "
    
  @defaultName: ->
    "Unidentified Person"

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

vs

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

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

  setName(name) {
    [this.firstName, this.lastName] = name.split(" ");
  }
  
  static defaultName() {
    return "Unidentified Person"
  }
}

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

I definitely like the way this is headed - no need for commas, no need to write function all over the place; but I'm in the "write less code" camp, so I definitely prefer the former (not to mention finding it far more readable). However this is a matter of tast so if you're happy with typing this. instead of @ and adding in all the extra curly brackets it definitely backs up Blake's statement that ES6 is a viable alternative.

Further to this I much prefer CoffeeScript's implementation of super, though I can see why ES6 went the way they did allowing you to call a different method on the object's super.

Interpolation

Clearly ES6's and CoffeeScript's string interpolations are very similar; CoffeeScript interpolates for normal "string"s, whereas ES6 uses \backtick escaped strings`(which are annoying to write in Markdown, by the way). CoffeeScript uses#{var}whereas ES6 uses${var}`. All much of a muchness at this point.

Where the difference really stands out is in the handling of whitespace - ES6 (or at least the 6to5 tool) includes all the whitespace between the `'s (including newlines and indentation), whereas CoffeeScript either joins with a single space in the case of simple " strings or preserves all whitespace accounting for indentation level in the case of """ strings. To my mind both of these behaviours are desirable, whereas ES6's is not, take for example:

(function() {
  function foo(bar, val) {
    if (bar) {
      var str = `This is quite a long first line
        so I wrap it to a second line and then
        append the value ${val}`;
    }
  }
})();

The output from passing this through 6to5's REPL is:

var str = "This is quite a long first line\n        so I wrap it to a second line and then\n        append the value " + val;

CoffeeScript equivalents:

do ->
  foo = (bar, val) ->
    if bar
      str = "This is quite a long first line
        so I wrap it to a second line and then
        append the value #{val}";
      str2 =
        """
        This is quite a long first line
        so I wrap it to a second line and then
        append the value #{val}
        """

produce

var str = "This is quite a long first line so I wrap it to a second line and then append the value " + val;
var str2 = "This is quite a long first line\nso I wrap it to a second line and then\nappend the value " + val;

I can't think of a situation where I'd prefer 6to5's implementation.

Fat Arrows, Default Arguments

Brilliant additions to the JS syntax, these behave the same as CoffeeScript's but with ever-so-slightly different syntax rules.

Splats

Another brilliant addition, but I find splats can be quite powerful in the middle of an argument list, particularly in Node.js-style callback situations so that the callback is automatically popped off the end. For example:

# Splat dereferencing
names = ["Alice", "Belinda", "Catherine", "Davina", "Emma", "Francine", "Georgia", "Harriet", "Iglesias"]
[firstName, middleNames..., lastName] = names

# Splat function args preserving callback
foo = (fn, args..., callback) ->
  results = (fn arg for arg in args)
  process.nextTick ->
    callback null, results

double = (a) -> a * 2

foo double, 80, 60, 40, (err, results) ->
  console.log results

Sadly ES6 only allows splats at the end, requiring you to then manually pop() the callback (or lastName), making your code longer and more challenging to understand.

Structuring/Destructuring

I must say I do like that ES6 lets you leave true blanks when doing var [first, , last] = [1, 2, 3] but using an underscore or similar is a one character workaround.

ES6 does object de/structuring pretty much the same as CoffeeScript (var {a, b} = {a: 1, c:3}, var {foo: a, bar: b} = {foo: 1, baz: 3} and var c = {a, b}) however there's a slight circumstance where CoffeeScript does it better: when referencing properties off of the current object, e.g. c = {@a, @b} (var c = {a: this.a, b: this.b}).

Things ES6 has that I wish CoffeeScript had

  • The ternary operator a ? b : c (if a then b else c is too verbose for my taste)
  • Computed (dynamic) property names, {[getKey()]: getValue()}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment