Skip to content

Instantly share code, notes, and snippets.

@bernar83

bernar83/blog.md Secret

Created October 26, 2017 21:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bernar83/b97a2e32c01a657e1e42c9a9919c1a9b to your computer and use it in GitHub Desktop.
Save bernar83/b97a2e32c01a657e1e42c9a9919c1a9b to your computer and use it in GitHub Desktop.

Grasping Javascript: this Keyword

this can be pretty hard to understand when first learning Javascript. Hopefully this article can help in grasping this a little easier (pun intended).

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 this binding.

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.

Example: https://gist.github.com/b7d8341af130e93d54fabc6d7e9274f5

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.

Example: https://gist.github.com/3198565d236804817a0ada145777b9d6

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.

Example: https://gist.github.com/229c34a087c7a51d882e2ab9a0d4a2c2

In the example, it may seem bar() should say "Adrian" since it looks like it would get the same value as obj.sayName but bar() is just another reference to sayName(). 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 apply() or call() method. Explicit binding allows you to not add the function as a property to the selected object. Instead, call() or apply() takes the selected object as its parameter and invokes the function on the specified object.

Example: https://gist.github.com/6a22e1e276750807a1993bfc59074b0e

In this example, this in sayName() explicitly binds to obj. Explicit binding allows you to force this binding to the object in call/apply's parameter. Note that call() and 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 this binding.

Example: https://gist.github.com/79b94a359eea5c0a78bb012b95a35dd8

Using the bind() method will now point this to the specified obj placed in its parameter.

4. new Binding

The last rule for this binding is the new binding. Although the keyword new is familiar to those who already know class oriented languages, it is not exactly the same. Javascript's "constructor" functions are not the same because they do not belong to any classes and are not instantiating a new class. Let's look at an example.

https://gist.github.com/70027e04a334c8fa633f52befd9d5754

When 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.

https://gist.github.com/c6ef9fbaf3f108cc90ff07fa0e7ea2bb

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.

https://gist.github.com/c128beed42015440fa7094bfe78712bf

In the example above new binding takes precedence over implicit binding.

Let's now see if new binding takes precedence over explicit binding.

https://gist.github.com/8a14eb0ceada9df20410000513a80b32

We notice 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 person to name with new, bob.name is "bob".

In summary, there are four questions to ask when figuring out the value of this.

  1. Is the function called with new binding? If yes, this value is the newly created object.

https://gist.github.com/1c5aa31acb8787871bbf12bae5cf81a4

  1. Is the function called with call or apply (explicit binding) or hard bound with bind? If yes, this value is the explicitly called object.

https://gist.github.com/a8ced5c4e52d30161b18687f2126f9bb

  1. Is the function called in the context of an object or is "owned" by one? this value is the context object.

https://gist.github.com/d57b7a968d6460061994545ed75265aa

  1. If all else fails then default binding is the answer and this is 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment