Introduction to arrow functions in JavaScript
Syntax
In order to understand arrow function syntax, we should start by refactoring a regular function step by step:
function square(a) { return a * a; }
We can start by refactoring the function declaration to use a variable assignment:
const square = function (a) { return a * a; }
Then, we can refactor the regular function
to an arrow function:
const square = (a) => { return a * a; }
If there's only one argument, we can omit the parentheses around it:
const square = a => { return a * a; }
If the function is a single expression, you can omit the curly braces and return
statement and use an implicit return:
const square = a => a * a;
Execution context
The main difference between arrow functions and regular functions is execution context (i.e. the value of this
). Technically speaking, most other differences often mentioned either stem from this one or are side effects of it.
In a regular function, this
is dynamic and depends on how the function was invoked:
function simple() { return this; } const object = { method() { return this; } }; class Class { classMethod() { console.log(this); } } const instance = new Class(); simple(); // `this` refers to the global object new simple(); // `this` refers to the newly created instance object.method(); // `this` refers to `object` simple.call(object); // `this` refers to `object` instance.classMethod(); // `this` refers to `instance` setTimeout( instance.classMethod, 0 // `this` refers to the global object );
Arrow functions, unlike regular ones, don't define their own execution context therefore this
inside an arrow function always refers to the lexical this
(i.e. the scope in which the arrow function was defined).
const simple = () => this; const object = { method: () => this }; class Class { classMethod = () => { console.log(this); } } const instance = new Class(); simple(); // `this` refers to the global object new simple(); // Uncaught TypeError: simple is not a constructor object.method(); // `this` refers to the global object simple.call(object); // `this` refers to the global object instance.classMethod(); // `this` refers to `instance` setTimeout( instance.classMethod, 0 // `this` refers to `instance` );
As you can see from these examples, there's a difference in how constructors work due to the execution context and how it's resolved. Regular functions can be used as constructors in contrast to arrow functions which will throw a TypeError
instead.
Moreover, arrow functions and regular functions present some differences when used to define class methods. A regular function method will end up with a different execution context when passed as a callback. This can be handled using Function.prototype.bind()
or by using an arrow function which doesn't have this issue.
If you want to read more about the this
keyword, you should check out our previous article on the subject.