The arrow function allows declaration of anonymous functions (lambda) in a more concise way. Let’s see what’s so great about it :).

Usage

1
2
const sayHello = (name) => console.log(`Hello ${name}`)
sayHello("World")

In ES5, this would be a bit more verbose.

1
2
3
4
var sayHello = function(name) { 
  console.log("Hello " + name)
}
sayHello("World")

Single argument

When only one parameter is required, the arrow function can be written without the brackets for the parameter like this:

1
2
const sayHello = name => console.log(`Hello ${name}`)
sayHello("World")

Although I much prefer keeping consistency by always having the brackets to indicate that they are parameters.

Much like in C#, the arrow function can be expression or block bodied.

Expression bodied arrow function means implicit return

Expression bodied arrow function implicitly returns a value.

So, as an example:

1
2
3
const add = (num1, num2) => num1 + num2
let result = add(2,3)
console.log(result)

is functionally the same as:

1
2
3
4
5
const add = (num1, num2) => {
	return num1 + num2
}
let result = add(2,3)
console.log(result)

When writing functions in functional style, it is preferred to write expression bodied functions because of the implicit return. The reason for this is simple - in functional programming, we always expect an output from a function.

Block bodied arrow function

When you’re wanting to simply declare a function as normal with the arrow function, you can use a block bodied arrow function - this allows you to declare a function as you would with a conventional function.

“this” Behaves Differently

this in an Arrow function is always lexically scoped - this means that this will always be what you expect it to be.

Let’s have a look an example to get a better understanding of how this behaves in a conventional function over arrow function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Hello {
  constructor(name) {
    this.name = name
  }
  
  changeName = (name) => {
    this.name = name
  }
  
  sayHelloArrow = () => {
    console.log(`hello ${this.name}`)
  }
  
  sayHelloFunction() {
    console.log(`hello ${this.name}`)
  }
}

let bryan = new Hello('Bryan');

bryan.sayHelloArrow() // hello Bryan
bryan.sayHelloFunction() // hello Bryan

let kevin = { name: 'Kevin' }
bryan.sayHelloFunction.call(kevin) // Hello Kevin
bryan.sayHelloArrow.call(kevin) // Hello Bryan

One of the most common mistakes that you’ll come across in JavaScript is the usage of setTimeout for waiting for some external script to load asynchronously. Here’s a simplified example of this mistake:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var scriptHasLoaded = false

setTimeout(function() {
  scriptHasLoaded = true
}, 1000)

function MyClass(name) {
  this.name = name
  
  function sayMyName() {
    console.log(this.name)
  }
  
  this.sayName = function() {
    if(scriptHasLoaded) {
      sayMyName()
    } else {
      setTimeout(this.sayName, 100)
    }
  }
}

var myObj = new MyClass('Bruce')
myObj.sayName() // Does not print name

Because window.setTimeout changes this, we usually have to have some workaround in place by capturing the object that we are referring to, in most cases, the actual object enclosing our function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var scriptHasLoaded = false

setTimeout(function() {
  scriptHasLoaded = true
}, 1000)

function MyClass(name) {
  var _this = this; // reference to `this`
  this.name = name
  
  function sayMyName() {
    console.log(_this.name) // we use it everywhere where we want lexical `this`
  }
  
  this.sayName = function() {
    if(scriptHasLoaded) {
      sayMyName()
    } else {
      setTimeout(_this.sayName, 100) // here too
    }
  }
}

var myObj = new MyClass('Bruce')
myObj.sayName()

That’s quite a few things to remember to try and avoid the mistake. Now let’s see how this can be simplified using ES6’s arrow function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var scriptHasLoaded = false

setTimeout(function() {
  scriptHasLoaded = true
}, 1000)

function MyClass(name) {
  this.name = name
  
  var sayMyName = () => {
    console.log(this.name)
  }
  
  this.sayName = () => {
    if(scriptHasLoaded) {
      sayMyName()
    } else {
      setTimeout(() => { this.sayName() }, 100)
    }
  }
}

var myObj = new MyClass('Bruce')
myObj.sayName()

So, what’s the usecase for the arrow function? Well, anywhere where you’re not depending on this to be change during runtime as it’s a more concise way of declaring a function, without the possibility of this changing to other values.