A common misunderstanding with arrow functions is that they're merely "syntactical sugar" for regular functions. In actuality, arrow functions bring their own benefits over standard functions in addition to making it easy to write one-liners. We'll be taking a look at the syntactical sugar aspects of arrow functions as well as a few of the more prominent functionality differences between arrow functions and standard functions.
What is an Arrow Function?
Arrow functions, as defined by the MDN Web Group, "is a syntactically compact alternative to a regular function expression, although without its own bindings to the this, arguments, super, or new.target keywords. Arrow function expressions are ill suited as methods, and they cannot be used as constructors."
MDN packs a bunch into that brief definition, and if you found it hard to digest don't worry. We're going to spend some time here unpacking that definition so you walk away fully comprehending what an arrow function is, when to use one, and when not to use one.
The Syntactical Sugar
For those brand new to arrow functions, let's go over exactly what an arrow function looks like compared to the standard function.
const standardFunction = function () { console.log('standard: do something here'); } const arrowFunction = () => { console.log('arrow: do something here'); } standardFunction(); arrowFunction();
Copied!
Your first thought might be, well that's not very compact compared to the standard function, and you're absolutely right! When we use arrow functions like a standard function, they look almost identical. The main difference being you drop the function
keyword and you add an arrow (=>
) just behind the parenthesis.
This, however, only scratch the surface of the arrow function's syntactical sugar capabilities.
Let's Kick It Up A Notch
So we've covered that arrow functions allow us to drop the function
keyword in favor of an arrow (=>
), however, that's not the only keyword they allow us to drop. Arrow functions give us the ability to omit curly braces and the return
keyword when we have a single-line arrow function. It's important to note that in order to omit the return
keyword you also need to omit the curly braces. It's a packaged deal. Even if your arrow function is on a single line, if you have curly braces, in order to return a value you'll need to include the return
keyword.
So let's incrementally adopt this single-line arrow function via a series of examples.
// 1. same arrow function structure as before const exampleOne = (someText) => { console.log('this is', someText); } // 2. since we have a single parameter, we can optionally drop the parenthesis const exampleTwo = someText => { console.log('this is', someText); } // 3. since we have a single line we can optionally drop the curly braces const exampleThree = someText => console.log('this is', someText); // 4. since we dropped the curly braces, whatever follows the => is returned const exampleFour = someText => 'this is ' + someText; // 5. we can add back the parenthesis at any time const exampleFive = (someText) => 'this is ' + someText; // 6. but if we add back the curly braces, we must add return to return a value const exampleSix = (someText) => { return 'this is ' + someText; } exampleOne('example one'); exampleTwo('example two'); exampleThree('example three'); console.log(exampleFour('example four')); console.log(exampleFive('example five')); console.log(exampleSix('example six'));
Copied!
I'd recommend copy/pasting this into your browser's console and inspecting the results. Once you've done that return back here and let's step through these examples.
Our first example is the same structure as our last arrow function example. We need a place to start from.
In example two, since our function only accepts one parameter, we can optionally remove the parenthesis around the parameter name. Note that if we were to add a second parameter we would need to put the parenthesis back otherwise JavaScript will throw an error.
With example three things take a jump forward. Since we only have a single line in our function, we can omit the curly braces and move our line up to directly after our arrow (
⇒
). It's important to note that since we have omitted the curly braces from our arrow function, it will now return the result of whatever our single-line is once the function is run. In this case, sinceconsole.log()
returnsundefined
so does our function.Now that we now from example three that our arrow function, without curly braces, will automatically returns it's result, we can use this to our advantage. Let's move our
console.log
around ourexampleFour
function call. This will log out whatever is returned fromexampleFour
when it's called. In this case it'll be, "this is example four."Note that at any point we are free to add back the parenthesis around our parameter.
However, if we add back the curly braces we will lose the automatic return for our arrow function. Therefore, we would need to explicitly tell the function to return a value using the
return
keyword.
Practical Example
So we've already covered a lot, and we haven't even gotten to the functionality of arrow functions yet. First I want to take a second from concatenating strings to give you a practical example of when an arrow function might make a lot of sense.
Grabbing a single field out of a collection
// Task ------------------------- // find the Matt Groening show, // Futurama by it's id, 2. // ------------------------------ // we have a collection (array of objects) that have an id and a title const collection = [ { id: 1, title: 'The Simpsons' }, { id: 2, title: 'Futurama' }, { id: 3, title: 'Disenchantment' } ]; // using a standard function const standardFuturama = collection.find(function(show) { return show.id == 2; }); // using an arrow function const arrowFuturama = collection.find(show => show.id == 2); console.log(standardFuturama); console.log(arrowFuturama);
Copied!
We can see through this example using the find array method where those omissions really start to become beneficial in our everyday code.
What About Returning an Object?
Your first instinct to return an object using arrow functions, might be business as normal, like the below.
const makeShow = (title) => { id: Date.now(), title: title } makeShow('The Simpsons');
Copied!
However, it's important to realize we're still working with a function. While our intention was to return an object, what we've really done is added curly braces to our arrow function. Meaning, JavaScript attempts to use id: Date.now(), title: title
as a function block statement.
To get around this, we can wrap our object with parenthesis. This will tell JavaScript that we aren't using a block function (a function with curly braces), and it'll return the result of what's inside our parenthesis.
const makeShow = (title) => ({ id: Date.now(), title: title }) makeShow('Futurama');
Copied!
The Functionality
Now before we use arrow functions within our code, it's imperative that we also understand some of the functionality impacts it has compared to the standard function.
This
Everyone's favorite keyword in JavaScript, this
, actually isn't bound to arrow functions. In many cases, this becomes a very powerful strength for arrow functions. It's also a very prominent reason in many cases for why you shouldn't use arrow functions.
Let's examine an example where you wouldn't want to use an arrow function because it doesn't get bound to this
.
Reason Against, Use-Case
Methods are one use-case where you typically wouldn't want to use an arrow function. A method, just in case you weren't entirely sure, is a function attached to an object.
const item = { name: 'T-Shirt', color: '#ebebeb', rightClick: function () { console.log('right click', this); }, leftClick: () => { console.log('left click', this); } } item.rightClick(); item.leftClick();
Copied!
Here, when we call item.rightClick()
we have access to the object's this
context, meaning we have access to both name and color via this.name
and this.color
. This is because we use a standard function for the rightClick
method, therefore, the object's this
is bound to our method.
However, when we call item.leftClick()
, since we use a arrow function the object's this
isn't bound to the method. Meaning this
inside our leftClick
method is the window's scope and we won't have access to either this.name
nor this.color
.
Reason For, Use-Case
One reason why you would want to use an arrow function to bypass this
being bound to your function is when you need to access the parent's this
within your function.
Let's rework our previous example at a little so that we have more going on inside our click. Imagine we want to perform an animation once the item's rightClick
method is called. We'll use two setTimeout
calls to animate in and out.
const item = { name: 'T-Shirt', color: '#ebebeb', rightClick: function () { console.log('right click', this); setTimeout(function () { console.log('standard function', this); // some animation handler here }, 1000); setTimeout(() => { console.log('arrow function', this); // another animation handler here }, 2000); } } item.rightClick();
Copied!
For our first timeout, we use a standard function. As a result, this
inside our first timeout is bound to the window instead of our item. Whereas with our second timeout, we use an arrow function. This bypasses the binding, resulting in this
remaining the same as and remaining bound to our item.
Arguments
Arrow functions aren't defined an arguments object. Therefore, any usages of arguments
within an arrow function will reference any parent-scoped arguments. In cases like the one below, where there isn't a parent-scoped arguments object, a ReferenceError
will be thrown.
const standardExample = function (someText) { console.log('this is', arguments); } const arrowExample = someText => { console.log('this is', arguments); } standardExample('standard'); arrowExample('arrow');
Copied!
In this example our standardExample
function logs the arguments object, containing "standard" under key 0
. Whereas, our arrowExample
actually errors out because the arrow function isn't given an arguments object and we also don't have an arguments object within our parent scope.
See the console output for this below.
Others
There are several other functionality changes arrow functions bring with them. These include usages of the new
keyword, yield
keyword, a lack of a prototype
, and a few others.
New Keyword
Arrow functions don't have the ability to be constructors. So, if you need to create a constructor function it's important to reach for a standard function over an arrow function.
const StandardMenuItem = function (title, href) { this.title = title; this.href = href; } const ArrowMenuItem = (title, href) => { this.title = title; this.href = href; } console.log(new StandardMenuItem('standard', '/standard')); console.log(new ArrowMenuItem('arrow', '/arrow'));
Copied!
When we attempt to use the new
keyword to construct a new ArrowMenuItem
, the error TypeError: ArrowMenuItem is not a constructor
will be thrown.
Yield Keyword
Unless a standard function is nested as a child inside an arrow function, the yield
keyword will not work. So, don't use arrow functions for generators.
const data = [ { id: 1, title: 'The Simpsons' }, { id: 2, title: 'Futurama' } ]; // standard function works fine const standardFunction = function* (items) { items.forEach(item => { yield item.title; }); } // arrow function errors out const arrowFunction = * (items) { items.forEach(item => { yield item.title; }); }
Copied!
Before we even call our arrowFunction
the error SyntaxError: yield expression is only valid in generators
will be thrown.
Prototype
The last functionality change we'll be covering regarding arrow functions is it's lack of a prototype
. It just doesn't have one.
const standardFunction = function () {}; const arrowFunction = () => {}; console.log('standard', standardFunction.prototype); console.log('arrow', arrowFunction.prototype);
Copied!
Here the standard function will log out it's prototype
, while the arrow function will log out undefined
.
What's Next?
I highly recommend playing around with arrow functions. Get comfortable with them. Not only do they become super handy in everyday JavaScript tasks, but they also make life a lot easier when working with popular frameworks, like React and Vue, as well.
We skipped a couple of smaller items regarding arrow functions in this post. If you're curious about the full feature set of arrow functions, be sure to check out MDN Web Group's documentation.
Join The Discussion! (0 Comments)
Please sign in or sign up for free to join in on the dicussion.
Be the first to Comment!