As we remember from the chapter Object methods, "this", arrow functions do not have this
. If this
is accessed, it is taken from the outside.
let group = { title: "Our Group", students: ["John", "Pete", "Alice"], showList() { this.students.forEach( student => alert(this.title + ': ' + student) ); } }; group.showList();
Here in forEach
, the arrow function is used, so this.title
in it is exactly the same as in the outer method showList
. That is: group.title
.
If we used a “regular” function, there would be an error:
let group = { title: "Our Group", students: ["John", "Pete", "Alice"], showList() { this.students.forEach(function(student) { // Error: Cannot read property 'title' of undefined alert(this.title + ': ' + student) }); } }; group.showList();
The error occurs because forEach
runs functions with this=undefined
by default, so the attempt to access undefined.title
is made.
That doesn’t affect arrow functions, because they just don’t have this
.
Not having this
naturally means another limitation: arrow functions can’t be used as constructors. They can’t be called with new
.
Arrow functions also have no arguments
variable. That’s great for decorators, when we need to forward a call with the current this
and arguments
.
That’s great for decorators, when we need to forward a call with the current this
and arguments
. For instance, defer(f, ms)
gets a function and returns a wrapper around it that delays the call by ms milliseconds:
function defer(f, ms) { return function() { setTimeout(() => f.apply(this, arguments), ms) }; } function sayHi(who) { alert('Hello, ' + who); } let sayHiDeferred = defer(sayHi, 2000); sayHiDeferred("John"); // Hello, John after 2 seconds
The same without an arrow function would look like:
function defer(f, ms) { return function(...args) { let ctx = this; setTimeout(function() { return f.apply(ctx, args); }, ms); }; }
Here we had to create additional variables args
and ctx
so that the function inside setTimeout
could take them.