Exploring ECMAScript 2015 (ES6): Arrow Functions

ECMAScript 2015 introduces a new function syntax: arrow functions. Arrow functions offer a more concise syntax, flexibility, and they inherit the lexical this from their surrounding code. The trade-off is the potential to introduce ambiguity to your code.

The new syntax drops the function keyword.

// ES2015
const doubleNumbers = [1, 2, 3].map(x => x * 2); // [2, 4, 6]

//ES5
var doubleNumbers = [1, 2, 3].map(function(x) {  
  return x * 2;
}); // [2, 4, 6]

There are other differences allowing the syntax to be even leaner.

With a single-line expression, you can drop the brackets, and the return is implicit. Multi-line statement blocks require brackets around the statements, and you must explicitly specify a return a value.

const doubleNumbers = [1, 2, 3].map(x => x * 2); // [2, 4, 6]  
const numbersPlusOne = [1, 2, 3].map(x => {  
  let addTo = 1;
  return x + addTo;
}); // [2, 3, 4]

When passing a single parameter you can omit the parentheses. If you are passing multiple parameters or no parameters the parentheses are required.

const doubleNumbers = [1, 2, 3].map(x => x * 2); // [2, 4, 6]  
const convertNumbersToOne = [1, 2, 3].map(() => 1); // [1, 1, 1]  
const numbersPlusIndex = [1, 2, 3].map((x, index) => x + index); // [1, 3, 5]  

One quick thing to note, if you are returning an object literal you must wrap it in parentheses. This is to prevent the object literal from being interpreted as a code block.

const assignNumbers = [1, 2, 3].map(x => {num: x}); // Error  
const assignNumbers = [1, 2, 3].map(x => ({num: x})); // [{"num":1},{"num":2},{"num":3}]  

The other feature setting arrow functions apart is they inherit the lexical this of their surrounding code. This is often more intuitive, and easier to work with. It means the end of hacks like var self = this; or .bind(this).

// ES5
var muppets = {  
  title: 'The Muppet Show',
  names: ['Kermit', 'Gonzo', 'Ms. Piggy', 'Fozzie Bear'],
  introduce: function () {
    var self = this;

    this.names.forEach(function (name) {
      console.log(self.title + ' presents ' + name);
    });
  }
}

muppets.introduce();

// ES2015
let muppets = {  
  title: 'The Muppet Show',
  names: ['Kermit', 'Gonzo', 'Ms. Piggy', 'Fozzie Bear'],
  introduce () {
    this.names.forEach((name) => {
      console.log(this.title + ' presents ' + name);
    });
  }
}

muppets.introduce();

That leaves the question of when to use the new arrow function syntax, and when to use a function declaration. You will want to use the traditional function syntax anywhere you would already receive a meaningful value for this—like when you are calling an object method. I think using the function keyword is more readable for named functions—except if the function is a single-line expression—and arrow syntax is the better choice for anonymous functions.

// no good
const muppets = {  
  name: 'Kermit',
  sayName: () => {
    console.log(this.name);
  }
}
muppets.sayName(); // Cannot read property 'name' of undefined

// good
const muppets = {  
  name: 'Kermit',
  sayName () {
    console.log(this.name);
  }
}
muppets.sayName(); // Kermit

// good
// Good for consistency
function increment(num) {  
  return num + 1;
}

//good
// I can't resist arrow syntax for expressions
const increment = num => num + 1; 


// no good
const divisibleByFive = n => {  
  if (n % 5 === 0) {
    return true;
  } else {
    return false;
  }
}

// good
function divisibleByFive(n) {  
  if (n % 5 === 0) {
    return true;
  } else {
    return false;
  }
}

Arrow functions give us a nice, lean syntax for functions, and some much appreciated flexibility. They are great for anonymous functions, especially simple, single-lines expressions with an implicit return—like a lot of pure functions used in functional programming. They are not a drop-in replacement for the traditional function syntax though. They each have their place, and having both options allows us to be more expressive in our code.

Further Reading

Tyler Walters

Written by Tyler Walters

Tyler Walters is a software engineer in Phoenix, Arizona. He is married to a beautiful woman and has three incredible daughters. He is interested in game development, writing, beer, and hot wings.