Hard to beat C# and CoffeeScript here
– Brendan Eich, Arrow Function Syntax Rationale
Since sometime back in the heady days of Firefox 22, Firefox gained the ability to use Fat Arrow Functions in JavaScript. Users of CoffeeScript (or, I guess, C#) will be familiar with the syntax. We’ve been using these in Firefox DevTools code for nearly 6 months.
You can use them today in any shipping Firefox and experiment with them live in the Scratchpad or Console.
They look like this:
let x = (args) => { /* some function gunk */ };
If you want to call it, you can with x();
Fat Arrow functions have a couple of interesting properties. First and probably most useful is that they gain the scope of the environment they’re defined in. You can’t change the value of this
by using a call()
or bind()
function.
Second, Fat Arrow functions don’t have their own prototype or a constructor. (They have the standard Function prototype). This means trying to use the new
operator on a fat arrow function results in a TypeError.
That’s all well and good, but what is the practical application of all of this? If you’re a JavaScript programmer, chances are you’ve seen (and done) something like this before:
var listener = node.addEventListener("click", function(event) { let _target = event.target; this.handleClick(_target); }.bind(this));
Inside we call a local method called handleClick() with the event’s target property. Nothing too exciting.
With Fat Arrow Functions, that becomes:
var listener = node.addEventListener("click", (event) => { let _target = event.target; this.handleClick(_target); });
Look at all that saved typing!
The real benefit of course is that you don’t have to go through the mental hoop-jumping of trying to figure out what scope your function is going to run in (and more often-than-not, you just wanted it to run inside the current scope the function is being defined in anyway).
It just does the right thing.
Some interesting facts about Fat Arrow Functions
You can use them recursively. Because the containing scope closes over the fat arrow function, you can do things like,
let fib = (n) => { if (n <= 1) return 1; return fib(n - 1) + fib(n - 2); }
You can’t use fat arrow functions as Generators. Deep continuations are not allowed. Fat Arrow functions are intended to be super light.
The “=>
” syntax behaves like a “low-precedence assignment” operation. In
let x = () => { }
the order of operation is from left to right.
Update!
I didn’t include it originally, but some Fat Arrow Enthusiasts encouraged me to mention expression function syntax.
let square = (x) => { return x * x };
is equivalent to:
let square = x => x * x;
For single arguments, you can leave off the ()s. And for function expressions, you can lose the {}s and the return statement. Note that you cannot even use a return statement in this case as it’ll generate a syntax error about a missing semicolon. Don’t even try it!
Trajectory Book 1 (Hard Scifi, 65k words)
Four mining ships are making the slow return to Mars from operations in the asteroid belt. Back on the planet, a group of students discover a mysterious object in space in an impossible orbit. The crew of the Lighthouse space station are shocked by a devastating accident that throws their routine into chaos as they strive to get their ships safely home.
Amazon US, Amazon Canada, Smashwords (epub), Kobo, iTunes
Why can’t they be generators?
It’d be awesome to use this kind of functions with Task.js!
I think the main reason you can’t use fat arrow functions as generators is that they lack a lot of the scope machinery full-fledged functions have on them. They’re “lighter”.
Continuations have to maintain a lot of extra state to work and would violate the simplicity of these constructs. Generators are expensive.
nice article rob.quite enlightening. if i’m correct this means that the fat arrow functions do not replace the current function convention.
Oh no, familiar function declarations will stick around. The world would break if that ever went away.
Thanks for the comment!
In theory with the old DOM interfaces all you had to do was to define a handleEvent method on your prototype and use
node.addEventListener(“click”, this);
Sure. I didn’t say this was the only way or even the best way to add an event listener. Just mentioning a pattern that has cropped up.
Also, using a handleEvent method in an object leads to a lot of:
switch(event.type) cases if you need to trap multiple events.
But this was about fat arrow functions…
and from HN:
https://news.ycombinator.com/item?id=6418337
Is there any way to distinguish regular functions from fat arrow functions? It seems that, at invocation, it might be useful to know whether or not ‘this’ needs to be assigned.
tgwhite: that’s an interesting question. I bet you could use the fact that you can’t call “new” on a fat-arrow function to determine if it’s a regular function.
typeof for both is “function”.
Just for kicks:
let isFatArrow = (functor) => {
try {
new functor();
} catch(e) {
return true;
}
return false;
};
function a() { return true };
isFatArrow(isFatArrow); // true
isFatArrow(a); // false
works. (sorry for the crappy formatting)
This is pretty awesome, especially coming from a C# background. Is this currently available or is it coming out soon?
jon, this is currently available in Firefox 22 and up. As part of ES6, it should make it to V8 and IE sometime in the near future.
I can’t get the let statement to work in jsFiddle: http://jsfiddle.net/simevidas/StXrK/. I get a “SyntaxError: missing ; before statement” error in Firefox’s console.
So, for the “let” statement to work, the code has to be placed in a script element with a type attribute that contains the “language” value, e.g. . On the other hand, arrow functions work in regular blocks. This should be noted in the article, since some people may try to test that code in their Firefox.
that’s really an issue with jsFiddle, not Firefox. If you run your example code directly in a Scratchpad or the Console it will work.
My mistake, I meant this: ᐸscript type=”text/javascript;version=1.8″ᐳ
A side-question, but why are you not using event.target directly in your function? Why the extra temporary value?
ix, no good reason. 🙂
I’ve written an npm module to detect if something is an arrow function or not – https://npmjs.org/package/is-arrow-function – it only works in Firefox at the moment, but will work in any runtime that supports arrow functions going forward!
There is a slight error in your definition of fib
let fib = (n) => {
if (n <= 1) return 1;
return fib(n – 1) + fib(n – 2};
}
You need to enclose n-2 in parentheses not a left parenthesis and a right curly brace.
right you are! I’ve fixed it.
(we just proved Open Source works) 🙂
@rob: nice trick using “new”, but it can have side-effects. What about fn.hasOwnProperty(“prototype”) though? Apparently working in Firefox and iojs with –harmony_arraow_functions.
Ahead of time this post was