Some lesser-known Coffeescript features you might not know about
Directly assign properties on this
from function
Often in function declarations – particularly constructor functions – we want to assign properties on this
from the function signature:
class Dog
constructor: (name, age) ->
@name = name
@age = age
We can clear this up a little with CoffeeScript’s destructuring syntax (note the array brackets – which are required, unlike Ruby):
class Dog
constructor: (name, age) ->
[@name, @age] = name, age
However, CoffeeScript allows the implicit assignment of properties on this
from the function signature, so we can just do this:
class Dog
constructor: (@name, @age) ->
No function body needed! Quite often this is all you’re doing in a constructor, so I find it’s not unusual for this to be the norm rather than the exception.
For the curious, this is what the example above is compiled into (omitting the outer IIFE) – pretty much the same as the first example:
var Dog;
Dog = (function() {
function Dog(name, age) {
this.name = name;
this.age = age;
}
return Dog;
})();
Shorthand for object assignment
How often have you written something like the following?
createDog = (name, age) ->
options = { name: name, age: age }
API.post "/dogs", options
If you’re naming your variable names sensibly, it’s pretty common to have the same name for a variable and the object property you’re assigning it to. Fortunately, CoffeeScript has a handy shorthand for just this case:
createDog = (name, age) ->
options = { name, age }
API.post "/dogs", options
This also works with properties on this
:
class Dog
create: ->
options = { @name, @age }
API.post "/dogs", options
Quick and easy closures
Invoking an asynchronous function for every item in a collection often introduces a subtle bug:
for url in pages
$.get url, (results) ->
doSomethingWith(url, results) # <- url will have changed at this point
Since JavaScript doesn’t have lexical closures (until ES6 is commonly available and we can use let
instead), the value of url
will have changed by the time the callback fires, since for
loops don’t introduce a new scope.
Luckily, CoffeeScript has our back in cases like this – the do
keyword:
for url in pages
do (url) ->
$.get url, (results) ->
doSomethingWith(url, results)
This defines an anomymous function to close over our requested variable (url
in this case), then invokes it.
Generally, this problem disappears if you break down your code into small, well-named functions, but it’s a useful feature nonetheless.
Summary
Any other CoffeeScript features I’ve missed? Let us know in the comments.
Photo by peter barwick on Flickr