I’ve been spending more time working with modern JavaScript (including learning about arrow functions) and I wanted to make some notes here regarding arrow functions (since some details about them were not intuitive to me at first).
Arrow functions are only supported in “modern” JavaScript (ES6), so they should only be used when your code is going to be transpiled (run through a tool to rewrite it in an older version of JavaScript (ES5) so it works on older browsers).
The two things arrow functions give us are:
- alternative syntax
- they inherit lexical context (
this
value)
Alternative Syntax
Arrow functions provide us with an alternative syntax that allows us to write our code in a different (shorter) way.
// Traditional JavaScript function syntax for code that multiples the parameter by itself.
// myFunc1(7) returns 49 because 7*7 is 49
function myFunc1(x) {
return x*x;
}
Historically, JavaScript allows you to define a function without a name (i.e. an anonymous function).
In the code below we are assigning our anonymous function to the variable myFunc2, so we can call myFunc2 the same
way we would a named function. This syntax is supported in older (ES5) JavaScript versions.
// This function has the same behavior as myFunc1().
// myFunc2(7) returns 49
var myFunc2 = function(x) {
return x*x;
};
Arrow functions allow us to eliminate the function
keyword (this syntax is only supported in “modern” (ES6) JavaScript).
var myFunc3 = (x) => {
return x*x;
};
Additionally, when we eliminate the braces ({}
) around the function,
JavaScript will assume we are returning the value.
var myFunc4 = (x) => x*x;
When there is only one parameter, we can also eliminate the parentheses ()
around the parameter being passed into the function.
var myFunc5 = x => x*x;
Returning an Object
When we return an object, this can create some confusion over whether the curl braces ({}
) indicate an object or a body of the function.
// Note: this will not work.
var myFunc6 = x => { squared: x*x };
In order to clarify for JavaScript that this is an object being returned (not a function body), we wrap the object in parenthesis ()
.
// Note: this will work.
var myFunc6 = x => ({ squared: x*x });
Arrow Functions Inherit Lexical Context (this
value)
The this
value in JavaScript can be a source of confusion. The short version is whenever a function is called, whatever is to the left of the period in front of the function name when called will have the value of this
in the function.
Example of this
In this example, when the sayName
function is called it is done with myObj.sayName()
, since the function is part of myObj
.
Since myObj
is to the left of the period in front of the function name when it is called, the value of this
inside sayName
will be myObj
.
This is why this.name
will give us the value of myObj.name
.
var myObj = {
name: 'sal',
sayName() {
alert(this.name);
}
};
myObj.sayName();
Lexical Context
We call the value of this
the lexical context.
e.g. in code we might see something like
commit.getHash()
which would call the function getHash()
on the object commit
with a lexical context of commit
(i.e. this
inside the function will be commit
).
Default Lexical Context
When a function is called without a period in front of it in a web browser, a default value of the window
object is used for this
.
This default lexical context can cause problems. In the example below, we’ve added a 500ms
delay before displaying the name
. To do this, we’ve wrapped the alert()
call in a function and put it in a setTimeout()
call.
But this causes a problem.
var myObj = {
name: 'sal',
sayNameWithDelay() {
setTimeout( function() {
alert( this.name );
}, 500 );
}
};
// This call results in an empty alert box because `window.name` is an empty string (`""`).
myObj.sayNameWithDelay();
The function wrapping alert()
defines a new this
(lexical context) and when the function is called by setTimeout()
, the default value of window
and window.name
is an empty string (""
) by default.
Arrow Functions do NOT have a new Lexical Context
Whatever the value of this
is before the function is called, stays the value of this
inside the function.
var myObj = {
name: 'sal',
sayNameWithDelay() {
setTimeout( () => {
alert( this.name );
}, 500 );
}
};
myObj.sayNameWithDelay();
by using the arrow function, the value of this
remains myObj
and our alert displays sal
.
Prior to Arrow Functions
Prior to arrow functions we solved the above situation by explicitly binding this
to our function
var myObj = {
name: 'sal',
sayNameWithDelay() {
setTimeout( function() {
alert( this.name );
}.bind(this), 500 );
}
};
// This works because we added `.bind(this)` to our function.
myObj.sayNameWithDelay();
or by setting this to an intermediary value so it would not be overwritten like in the following
var myObj = {
name: 'sal',
sayNameWithDelay() {
var that = this;
setTimeout( function() {
alert( that.name );
}, 500 );
}
};
// This works because we `that` is set to `myObj`
myObj.sayNameWithDelay();
Leave a Reply