Functions and scope
A tutorial to JavaScript Arrow Functions
Learn JavaScript arrow function syntax, implicit returns, lexical this, rest parameters, and when a regular function is the better choice.
Arrow functions are a shorter way to write function expressions. They landed in ES2015. The syntax is nice, but the real difference is how they handle this.
See the MDN arrow functions reference for the full grammar.
Arrow function syntax
This regular function expression:
const greet = function(name) {
return `Hello, ${name}`
}
becomes:
const greet = name => {
return `Hello, ${name}`
}
Use parentheses when there are zero parameters or more than one:
const getMessage = () => 'Hello'
const add = (a, b) => a + b
With exactly one simple parameter, parentheses are optional:
const double = number => number * 2
Defaults, destructuring, and rest parameters need parentheses:
const greet = (name = 'friend') => `Hello, ${name}`
const getName = ({ name }) => name
const sum = (...numbers) => numbers.reduce((total, number) => total + number, 0)
Implicit return
An expression body returns that expression without return:
const double = number => number * 2
double(4) //8
Add curly braces when you need multiple statements, then use return explicitly:
const double = number => {
const result = number * 2
return result
}
Wrap an object literal in parentheses when you want an implicit return:
const createUser = name => ({ name })
createUser('Flavio') //{ name: 'Flavio' }
Without the parentheses, JavaScript treats { as the start of a function body.
Arrow functions use lexical this
An arrow function captures this from the code around it. Changing the caller does not change that binding.
That helps inside callbacks:
const counter = {
value: 0,
start() {
setInterval(() => {
this.value += 1
}, 1000)
}
}
The arrow callback shares this with start().
Do not use an arrow function as an object method when you need this on the object:
const car = {
model: 'Fiesta',
manufacturer: 'Ford',
fullName() {
return `${this.manufacturer} ${this.model}`
}
}
car.fullName() //'Ford Fiesta'
Regular methods get this from the call site. Arrow functions do not.
Arrow functions in event listeners
With a regular listener, this is event.currentTarget:
const link = document.querySelector('#link')
link.addEventListener('click', function(event) {
this === event.currentTarget //true
})
An arrow listener inherits outer this. Use event.currentTarget when you want the element:
link.addEventListener('click', event => {
console.log(event.currentTarget)
})
Other differences from regular functions
Arrow functions also skip their own arguments, super, and new.target. Use rest parameters instead of arguments:
const logValues = (...values) => {
console.log(values)
}
They cannot be constructors:
const Person = name => ({ name })
new Person('Flavio') //TypeError
They cannot be generator functions either.
My advice: reach for arrow functions in short callbacks where you want lexical this. Use regular functions for constructors, generators, and methods that need dynamic this.
Lesson completed