DEV Community

loading...

What About These Fat Arrow Functions?

kuddleman profile image Donny ・4 min read

When I first started learning JavaScript a couple years ago, I was taught to write the classic arrow expressions:

function myMessage( ) {
   console.log(Hello, World!)
}

Enter fullscreen mode Exit fullscreen mode

Then I started using the new-fangled arrow function ES2015 way of
writing the same thing:


const myMessage = ( ) => {
   console.log(Hello, World!)
}

Enter fullscreen mode Exit fullscreen mode

The new syntax seems cool to me, but then I found out there were some important differences between the new and the old syntax. Sometimes those differences made arrow functions really amazing and other times, they caused unforeseen problems.

First, let’s go over some basics:

Omitting Parentheses.

Normally, we use parentheses to define the parameters our arrow function:


const addTwoNumbers = ( x, y ) => {
   return x + y
}

Enter fullscreen mode Exit fullscreen mode

Above, we’ve put parentheses around our two parameters, x and y.

We also must use parentheses if we have zero parameters:


const mySecretMessage = ( ) => {
   console.log(This is fun)
}

Enter fullscreen mode Exit fullscreen mode

However, if we have just one parameter, we can optionally omit the parenthesis:


const sayMyName = (string) => {
   console.log (string)
}

// we could have eliminated the parenthesis since there
// is only one parameter in our arrow function. 

// Let’s rewrite it:

const sayMyName = string => {
   console.log (string)
}

Enter fullscreen mode Exit fullscreen mode

To summarize: you can only omit parentheses around the parameters of an arrow function if you have one parameter. If you have zero, two, three or more parameters, you must use parentheses.

Omit the Curly Braces

When we have just one statement in our function body, we can simplify the statement by vomiting the curly braces:

This function with only one statement in the function body:


//Example A

const addTwoNumbers = ( x, y ) => {
   return x + y
}

Enter fullscreen mode Exit fullscreen mode

Becomes this:

//Example B

const addTwoNumbers = ( x, y ) =>   return x + y
}

Enter fullscreen mode Exit fullscreen mode

Cool! In the re-written statement, we 1) removed the curly braces, 2) removed the keyword “return” and 3) put the function body statement on the same line as the function definition.
Note the use of a couple of new vocabulary words. in Example A above, when we use the return keyword it is known as an explicit return. In contract, when we omit the return keyword as in Example B, it is called an implicit return.

***An Outlier Occassion Where Parentheses Are A Must:

If you’re going to return an object literal, then you must wrap that object in parentheses:


const greetings = name =>({ message: `Hello, ${ name }!`})

//now call “greetings”

greetings(Timmy)    // -> { message: Hello, Timmy! }

Enter fullscreen mode Exit fullscreen mode

If we don’t wrap the object literal in parentheses, then JavaScript will confuse the curly braces with those that define the function body.

The Famous “This”

The “this” keyword is a well-known bugaboo for many a JavaScript programmer. And to make it more fun, the “this” keyword acts differently in a classic function call vs. an arrow function call.

Let’s look at how “this” works in a method of an object.

See the method below:

const car = {
  model: 'Fiesta',
  manufacturer: 'Ford',
  fullName: function() {
    return `${this.manufacturer} ${this.model}`
  }
}
Enter fullscreen mode Exit fullscreen mode

Above you see the object “car”. Look at the key “fullName”. The value corresponding to “fullName” is a classic anonymous function.

In this case, when we call the fullName function like this:

car.fullName( )
Enter fullscreen mode Exit fullscreen mode

because we’re using a classic function, JavaScript knows to look for the meaning of “this” in the object it’s being called in. In our case, the “this” is being called in the object named “car”. Good, now JS will know how to parse the literals “this.manufacturer” and “this.model”. We just said the “this” must refer to the “car” object, so we we have “manufacturer” and a “model” property in our “car” object? Yes, we do! So JS can return:

car.fullName( )  // returns: “Ford Fiesta”
Enter fullscreen mode Exit fullscreen mode

Now let see what would happen if we turn our car.fullName method into an arrow function like this:

const car = {
  model: 'Fiesta',
  manufacturer: 'Ford',
  fullName: () => {
    return `${this.manufacturer} ${this.model}`
  }
}
Enter fullscreen mode Exit fullscreen mode

What happens now when we try to call “car.fullName( )” ?
The difference lies in the fact how the arrow function will interpret the “this” keyword. We already saw how the classic function knew that “this” referred to the object itself and therefore all the object’s key/value pairs were made available to that function.

However, our arrow function interprets the “this” keyword differently.

Our arrow function will only look for a meaning of “this” in its lexical scope meaning the context where that function is executed.

In other words, this is the only thing our arrow function “sees”:

fullName: ( ) => {
  return `${ this.manufacturer} ${ this.model }`
Enter fullscreen mode Exit fullscreen mode

Our arrow function only sees the parts of the object that directly concern its own execution. It does not see the “model” property nor does it see the “manufacturer” property.

Therefore, when our fat arrow method function tries to interpret “this.manufacturer” and “this.model” it finds no references to anything like that. Both values will be returned as undefined.

car.fullName(  )  // “undefined undefined”
Enter fullscreen mode Exit fullscreen mode

The upshot of all “this” is: when constructing a method in an object, you have to use the classic function keyword.

Discussion (0)

pic
Editor guide