this has been bewildering at times. The keyword
this can mean different things for ES5 functions than it does for ES6 (arrow) functions.
After three weeks of using the language, I’ve come to learn a good rule of thumb: always use arrow functions. But I was curious why there is a difference so I looked into it.
It turns out that arrow functions use what’s called lexical scoping. This means that the function always defines its
this by where the function was declared. If it was declared in the global scope,
this will always refer to the global scope. If it was declared within an object,
this will always refer to the object.
Furthermore, if an arrow function
foo is declared within another function
foo will define
this based on what
ES5 functions are not this straightforward. ES5 functions define
this based on what is executing them. If an ES5 function called
foo is declared in the global scope but invoked within another function
bar, the original function
this will be the function in which it was invoked,
foo is used as a callback for an event listener, its
this will actually be the node on which the listener was set. The definition of
this relies on the context in which the function is invoked.
This has some interesting and unsuspected consequences. Take the below example:
If we create a new instance of the object
Person like this:
const mike = new Person(“Mike”, “Sup?”) and invoke the function
mike.saySaying(), we get the expected result of logging “Hey!” to the console.
But when we try invoking the second method,
speak(), something strange happens.
speakSaying() doesn’t have access to the
this.name property in the
Person object because its
this is actually the function
speak() doesn’t have a
this.name property. This is a little perplexing, but never fear: arrow functions are here to save the day.
If we change the
speakSaying() function to arrow notation, the problem is fixed.
Now, invoking the function on our object instance produces the expected result.
The arrow function retains the concept of
this in which it was declared.
If we want to keep the function in ES5 notation, we can fix this issue instead by using the
Function.prototype.bind() method. This method allows us to define the function’s
After we declare the function
speakSaying(), we bind it to the
this, which is the
Person object, causing the
speakSaying() function to behave in the same way it did using arrow notation.
This would also work if the
speakSaying() function is declared outside of the
bind() method will not change an arrow function’s
this. This means that ES5 function notation is useful if you need control over a function’s definition of
this. Most of the time, though, it’s best to stick with arrow functions.