More on why that is later, but for now I thought I would start out by saying yes the this keyword is a little tricky. Once you think you have this all snuffed out you end up leaning more about it.
It would seem that typically in most cases the this keyword refers to the global object at the top level when it is code that is executed at the top level. As far as I can tell it would appear that this is always the case. If the code is at the top level this will refer to whatever the global object is in the environment.
This is where things can get a little confusing, as the this keyword can change depending on a lot of factors. I will cover as many of them as I am aware of here.
If you use this inside an IIFE, and do not do anything to change the state of this by using call, apply, or the new keyword, then the this keyword will continue to do the same as when it is top level code.
This is why I see that expression that I mentioned earlier, sometimes getting the global object is not that easy when you are trying to design code that will work in any run time environment. As such you just have to use some conditionals.
The new keyword is used when calling a function to create a new instance of a constructor function. Writing something about constructors, Classes, and the prototype chain is outside the scope of this post. So I will just say that constructors come in handy when you want to make a whole bunch of objects that share a set of methods.
If you just call Foo normally it will result in the global object or undefined like always, however if you call it with the new keyword it will return an object that is an instance of the Foo constructor.
When creating a class there is the prototype object of that class that is being made. All objects have a prototype object as one of their properties that contain methods that act on an instance of that constructor. The this keyword inside one of these methods refers to the instance of that constructor.
monkey patching is often considered bad practice, but yes if you really want to you can extent built in constructors, even Object.
If you monkey patch the Object prototype, this will refer to whatever object you call the method on.
I wrote a full post on Call,Apply, and Bind, but have also got into depth with it here.
Call is a way that you can call a method on any object, regardless if it is an instance of it’s prototype or not. It works by changing the value of this to whatever object you give it.
One example of how this comes in handy is with instances of HTMLCollection. They are array like, but are not instances of the constructor Array, therefore they do not have methods such as Array.forEach. So one way to quickly loop over an HTMLCollection is to use call, and give the collection as the first argument.
With call the first argument is the value you want this to be, and every argument after that is just the normal set of arguments that you would give to the method. In the case of Array.forEach it is the method I want called for each element of an array.
Apply works in the same way as call only you give it just two arguments the second of which is an array of arguments that are to be used with the method you are using with Apply.
Here I am again using an Array method on an instance of HTMLCollection. in this case it is slice which returns an instance of Array that is a section from the HTMLCollection with the given index values in the array that I have given apply as the second argument.
I could use call in the same way like this:
Not all methods work though If I used Array.splice that would cause and error as the HTMLCollection instances are read only. Call, and Apply can be used anywhere where appropriate, including your own methods that are part of the Constructors that you define.
Bind creates and returns a new function with the value of this set to the object that is given.
High level functions are fun, they are what happens when you accept a function as an argument, and pass some variables to it. In addition the this keyword can refer to whatever I want it to be, including a local variable.
In an event handler this refers to the relevant element.
So the this keyword is a little strange, hopefully this post will shed some light on the subject.