this a little easier (pun intended). If you prefer to see the code blocks with text instead of pressing links go here.
Looking for the Call-Site
It is best to understand where
this is a reference to by looking at where a function is called. Emphasis on where the function is called and not where it is declared. We are looking for the call-site because it's the only thing that matters for
Let’s look at an example of what call-sites are: https://gist.github.com/5cc762b79099e95cc295d32e6adbb8d4
Knowing the call-site allows us to better understand where
this is binding to.
The 4 Rules
There are four kinds of rules that help what
this binds to. Utilizing these four rules when insepcting call-sites will help in better understanding
this. The four rules are default binding, implicit binding, explicit binding, and new binding. We'll go into depth on these rules.
1. Default Binding
The most common call-site is the default binding and to be referred to when none of the other rules apply.
The first thing to note is the global-scope. Here, variable
word is in the global scope and, therefore, the global object property is
word = 'hello'. The second thing to note is to look at the call-site,
foo(). It's just an ordinary reference for the
function foo() and
this.word would resolve to that call, which points to the global object.
2. Implicit Binding
The second rule to remember is if the call site is in the context of an object.
There are a few different things to notice in the example above. The first is how
sayName() is referenced on the
obj object and at the call-site
sayName() is called as a property for
obj. So in a sense the
sayName() function is "owned" by
obj. Therefore, from the implicit binding rule, the
this keyword points and binds to the
obj object. The reason why I quoted "owned" is because of some problems that can happen if implicit ruling is applied.
A frustration that comes with implicit binding is how an object can lose its
this binding. The default rule is used when the implicit rule loses its binding, which then binds to the global object or is undefined.
In the example, it may seem
bar() should say "Adrian" since it looks like it would get the same value as
bar() is just another reference to
bar is just getting a reference to
obj.sayName but not invoking it. What matters is how the call-site looks like.
bar() is just an undecorated function call so default binding is in effect and
obj.sayName when declaring
bar just a reference.
3. Explicit Binding
Explicit binding can happen by invoking a function’s
call() method. Explicit binding allows you to not add the function as a property to the selected object. Instead,
apply() takes the selected object as its parameter and invokes the function on the specified object.
In this example,
sayName() explicitly binds to obj. Explicit binding allows you to force
this binding to the object in call/apply's parameter. Note that
apply() are similar but differ in their additional parameters.
Unfortunately, explicit binding alone doesn’t rid us of the perils of a function “losing” its
this binding. Functions can still "lose" its binding or even be paved over by frameworks.
Enter hard binding, a variation of explicit binding which helps us get around losing the
Using the bind() method will now point
this to the specified
obj placed in its parameter.
The last rule for
this binding is the
new binding. Although the keyword
new is placed in front of a function a
new object is created, that object is prototype linked, and
this binding is pointing to that object.
Which Has Priority
Let’s review the four rules and apply them to see which rule will take precedence over the other.
In the case above, explicit binding is precedent over implicit binding.
Now let’s see
new binding's precedence in what we have so far.
In the example above
new binding takes precedence over implicit binding.
Let’s now see if
new binding takes precedence over explicit binding.
new binding didn't change
person.name's value but the
new binding created a new object who's name property is "bob". Although we bound
bob.name is "bob".
In summary, there are four questions to ask when figuring out the value of
- Is the function called with
newbinding? If yes,
thisvalue is the newly created object.
- Is the function called with
apply(explicit binding) or hard bound with
bind? If yes,
thisvalue is the explicitly called object.
- Is the function called in the context of an object or is “owned” by one?
thisvalue is the context object.
- If all else fails then default binding is the answer and
thisis the global object.
Those are the 4 rules that help illuminate what
this value is.
I hope reading this article helps in understanding
this a little more. If you found it helpful don't forget to leave a few claps.
Originally published at gist.github.com.