Different Behaviors of Javascript Functions
By: Travis Prol
Tags: JavaScript, Functions In Javascript, React, This, Software Development

A Look at What the Arrow and Key Word Does to “this”

During my time in the software engineering program at the Flatiron School, I always thought that functions declared with the function key word and arrow functions behaved the same, and that arrow functions were just a more advanced way of writing it. It wasn’t until I made a lazy mistake (this IS the best way to learn) that I realized that these two ways of declaring functions have different affects on the this key word.

Let’s take a look at the two functions below and what happens when we invoke them:

function sayMyName () {

name = "Travis"

return this.name

} sayMyName() // => "Travis"

sayMyName = () => {

name = "Travis"

return this.name

} sayMyName() // => "Travis"

As you can see, both of these functions return “Travis” when they are invoked. In both cases, this is inside of the scope of both of these functions and this.name refers to the name attribute of that function.

The change of behavior happens when we try to call these functions on an object. Let’s consider just the function keyword version and see what happens when we invoke it on an object that has a name key/value pair, and a reference to the function:

function sayMyName () {

name = "Travis"

return this.name

} let catt = {

name: "Catt",

sayMyName: sayMyName

} let scott = {

name: "Scott",

sayMyName: sayMyName

} sayMyName() // => "Travis"

catt.sayMyName() // => "Catt"

scott.sayMyName() // => "Scott"

As you can see above, calling a function that uses the function key word changes what this refers to. In this case, this refers to the object that the function is invoked on, either the catt object, or the scott object.

Now let’s look at the arrow function version:

sayMyName = () => {

name = "Travis"

return this.name

} let catt = {

name: "Catt",

sayMyName: sayMyName

} let scott = {

name: "Scott",

sayMyName: sayMyName

} sayMyName() // => "Travis"

catt.sayMyName() // => "Travis"

scott.sayMyName() // => "Travis"

In this case, it returns “Travis” every time because when this is used in an arrow function, it is bound to the scope of the function that it is inside of therefor binding this.name to the value of “Travis” no matter what object the function is invoked on.

This binding to the scope action is exactly why we always want to use arrow functions in class-based components in React.js. Consider the following basic component:

class Button extends React.Component {

state = { greeting: "Hello World!" } clickHandler () {

this.setState({greeting: "Goodnight World!"})

} render() {

return (

<>

<h1>{this.state.greeting}</h1>

<button onClick={this.clickHandler}>Click Me</button>

</>

)

}

} export default Button

The expected action here would be to change the text on the screen from “Hello World!” to “Goodnight World” when the button is pushed. When the button is pressed, however, we get an error of Cannot read property ‘setState’ of undefined . Because we are using the function keyword, the value of this is bound to the object that we called it on which in this case is nothing, making it undefined.

To make this work, simply change the format of the clickHandler function into an arrow!

class Button extends React.Component {

state = { greeting: "Hello World!" } clickHandler = () => {

this.setState({greeting: "Goodnight World!"})

} render() {

return (

<>

<h1>{this.state.greeting}</h1>

<button onClick={this.clickHandler}>Click Me</button>

</>

)

}

} export default Button