Dissatisfied with the other answers. The top voted answer as of 2019/3/13 is factually wrong.
The short terse version of what =>
means is it's a shortcut writing a function AND for binding it to the current this
const foo = a => a * 2;
Is effectively a shortcut for
const foo = function(a) { return a * 2; }.bind(this);
You can see all the things that got shortened. We didn't need function
, nor return
nor .bind(this)
nor even braces or parentheses
A slightly longer example of an arrow function might be
const foo = (width, height) => {
const area = width * height;
return area;
};
Showing that if we want multiple arguments to the function we need parentheses and if we want write more than a single expression we need braces and an explicit return
.
It's important to understand the .bind
part and it's a big topic. It has to do with what this
means in JavaScript.
ALL functions have an implicit parameter called this
. How this
is set when calling a function depends on how that function is called.
Take
function foo() { console.log(this); }
If you call it normally
function foo() { console.log(this); }
foo();
this
will be the global object.
If you're in strict mode
`use strict`;
function foo() { console.log(this); }
foo();
// or
function foo() {
`use strict`;
console.log(this);
}
foo();
It will be undefined
You can set this
directly using call
or apply
function foo(msg) { console.log(msg, this); }
const obj1 = {abc: 123}
const obj2 = {def: 456}
foo.call(obj1, 'hello'); // prints Hello {abc: 123}
foo.apply(obj2, ['hi']); // prints Hi {def: 456}
You can also set this
implicitly using the dot operator .
function foo(msg) { console.log(msg, this); }
const obj = {
abc: 123,
bar: foo,
}
obj.bar('Hola'); // prints Hola {abc:123, bar: f}
A problem comes up when you want to use a function as a callback or a listener. You make class and want to assign a function as the callback that accesses an instance of the class.
class ShowName {
constructor(name, elem) {
this.name = name;
elem.addEventListener('click', function() {
console.log(this.name); // won't work
});
}
}
The code above will not work because when the element fires the event and calls the function the this
value will not be the instance of the class.
One common way to solve that problem is to use .bind
class ShowName {
constructor(name, elem) {
this.name = name;
elem.addEventListener('click', function() {
console.log(this.name);
}.bind(this); // <=========== ADDED! ===========
}
}
Because the arrow syntax does the same thing we can write
class ShowName {
constructor(name, elem) {
this.name = name;
elem.addEventListener('click',() => {
console.log(this.name);
});
}
}
bind
effectively makes a new function. If bind
did not exist you could basically make your own like this
function bind(functionToBind, valueToUseForThis) {
return function(...args) {
functionToBind.call(valueToUseForThis, ...args);
};
}
In older JavaScript without the spread operator it would be
function bind(functionToBind, valueToUseForThis) {
return function() {
functionToBind.apply(valueToUseForThis, arguments);
};
}
Understanding that code requires an understanding of closures but the short version is bind
makes a new function that always calls the original function with the this
value that was bound to it. Arrow functions do the same thing since they are a shortcut for bind(this)