Javascript: The 'this' keyword [context] cheatsheet
Tags: javascript, typescript, webdev
Published: 2021-01-25 05:57:02

**Javascript context** i.e the **'this'** keyword is quite a confusing topic in itself. Although, being very simple and semantic, it has been easy for me to forget the rules around context. With further ado, Let me introduce the cheatsheet for **the infamous 'this' keyword!**

<I>`Quick side note: This article is intended as a cheatsheet around JS context, It does not serve as a verbose explanation of the concept. If you are beginner and have not explored the 'context' concept yet, I highly recommend you to read this` [MDN doc](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this) `first 
`</I>
## Cheatsheet:
<table>
<tr>
<th>Use case</th>
<th>this</th>
<th>Example</th>
</tr>
<th colspan=3>Normal Functions</th>
<tr>
<td><b>Invoked directly</td>
<td><b>window</td>
<td>
<pre>
 fn() 
 // this -> window
</pre>
</td>
</tr>

<tr>
<td><b> Invoked from object<br>[Implicit Binding]
 </td>
<td><b> Invoking object </td>
<td>
<pre>
obj.fn()
// this -> obj
</pre>
</td>
</tr>
<tr>
<td><b> Explicit Binding<br>(bind, call, apply)
 </td>
<td><b> Passed reference
 </td>
<td>
<pre>
// --- .call .apply --- //
obj.fn.call(otherObj)
// this -> otherObj
<br>
// --- .bind --- //
const boundFn = obj.fn.bind(otherObj)
boundFn()
// this -> otherObj
</pre>
</td>
</tr>

<tr>
<td><b>Invoked in
<br>strict mode
</td>
<td><b>undefined <br><I>[[ If this->window ]]</I></td>
<td>
<pre>
'use strict'
fn()
// this -> undefined

window.globalFn = fn
window.globalFn()
// this -> undefined

obj.fn.call(window)
// this -> undefined
</pre>
</td>
</tr>

<th colspan=3>Arrow Functions</th>
<tr>
<td colspan=3>
<br><b>Instantiation context:</b> <i>
The value of 'this'[Context] when an object instance is created using a constructor.
</i>
</td>
</tr>
<tr>
<td><b> Invoked <br>
[directly OR from object] <br>
 </td>
<td><b> Instantiation context
 </td>
<td>
<pre>
// ----- direct invocation ---- //
// Instantiation context: window
const fn = () => console.log(this)
fn() 
// this -> window

// ----- invocation from obj [class instance] ---- //
function myClass(){
 this.fn = () => console.log(this)
}
-- OR --
class myClass {
 constructor(){
  this.fn = () => console.log(this)
 }
}
// Instantiation context: obj1
const obj1 = new myClass() 
obj1.fn()
// this -> obj1


// ----- invocation from obj ---- //
// Instantiation context: window
const obj2 = { fn: () => console.log(this) }
obj2.fn()
// this -> window
</pre>
</td>
</tr>
<tr>
<td><b> Explicit Binding <br>(bind, call, apply)
 </td>
<td><b> Instantiation context <br>
[No Effect] </td>
<td>
<pre>
obj.fn.call(otherObj)
// this -> window

instance.fn.call(otherObj)
// this -> instance
</pre>
</td>
</tr>

<tr>
<td><b> Invoked <br>
in strict mode 

 </td>
<td><b> undefined <br>
<I>[[ if this -> window ]]</i> </td>
<td>
<pre>
'use strict'
fn()
// this -> undefined
</pre>
</td>
</tr>
</table>

## Some simple examples🤥:

<pre>
 const fn = function(){
  console.log(this)
 }
 
 const obj = { 
  fn1: fn,
  fn2: function() {
   fn()
  },
  fn3: function(){
   this.fn1()
  },
  fn4: fn.bind(obj),
  fn5: function(){
   this.fn1.call(obj)
  }
 }
 
 obj.fn1()
 // log: obj 
 // as 'fn1' was invoked via the obj object

 obj.fn2()
 // log: window
 // as 'fn2' was invoked via the obj, but
 // the inner 'fn' was invoked directly 

 obj.fn3()
 // log: obj
 // fn3 was invoked via the obj, 'this' pointed to the
 // 'obj'. As 'this' -> obj, the inner execution
 // [this.fn()] is as good 
 // as obj.fn1()

 obj.fn4()
 // log: obj
 // Explicit context binding ;)

 obj.fn5()
 // log: obj
 // hope you're getting a hang of it :P
</pre>

## Some more simple examples 🤥🤥🤥:
<pre>

 function fnConstructor(){
  const fn = () => console.log(this)
  this.fn1 = () => console.log(this),
  this.fn2 = function(){
   console.log(this)
  }
  this.fn3 = fn,
  this.fn4 = function(){
   fn()
  }
  this.innerObj = { fn }
 }

 const obj = new fnConstructor()
 const obj2 = {
  obFn1: obj.fn1,
  obFn2: () => console.log(this)
 }

 obj.fn1()
 // log: obj (Instantiation context!)
 
 obj.fn2()
 // log: obj (Duhh^^)

 obj.fn3()
 // log: window ;)
 
 obj.fn4()
 // log: obj (Instantiation context!) 

 obj.innerObj.fn()
 // log: obj (Instantiation context!!) 

 obj2.obFn1()
 // log: obj (Instantiation context!!!)

 obj2.obFn2()
 // log: window ;) 
</pre>
----
<img src="https://media.giphy.com/media/iPiUxztIL4Sl2/giphy.gif" />
<b>Hope that was helpful 😇 </b>
If you have any questions/confusions/suggestions/corrections, Please do post down in the comments section below.

<b>Rohan Salunke</b>: [LinkedIn](https://www.linkedin.com/in/rohan-salunke/) [Twitter](https://twitter.com/ROHANSA09177528)