Master JavaScript “this” keyword to pass job interview
Tags: javascript, interview, webdev, beginners
Published: 2024-06-25 18:00:00

## Glossary

**Lexical scope** aka _lexical context_ or _scope_.  
Determines which variables and functions can be accessed by a part of a code. For example, `const` variable, defined inside a code block can’t be accessed outside that block.

```js
{  
  const blockScopedVar = 1  
}  
console.log(blockScopedVar) // Error. blockScopedVar is not defined
```

In this example, _lexical scope_ of `console.log()` does not contain `blockScopedVar`.  
Under the hood, _lexical scope_ is defined by _lexical Environment chain._

**Execution context**
In simplified terms, it is an environment, in which the current function is running. JavaScript code is executed by dividing the code into ‘pieces’ and running them sequentially. These ‘pieces’ are execution contexts. Execution context created for global context and per each function call. When a function being invoked, execution context is created. Execution context contains a value of `this`, _lexical scope,_ and other internal stuff required to run this function.

**"this" keyword**
`this` keyword is usually used in methods or classes, making it easy to point the function to an object’s properties we want to use. `this` in JS is just a reference to an object. This reference can be set:

- implicitly (when a new _execution context_ is being created)
- explicitly (with `call()`, `apply()`, `bind()` methods).

The implicit value of `this` is determined by where in the code `this` is being used (in what context). This is causing most confusion and the way to sort this out is to know what `this` contexts exist and how they affect the value of `this`.

## Implicit contexts

At the creation phase of _execution context,_ the value of `this` is assigned automatically, based on where `this` in code is being used. Sometimes this is called `this` _context_ (not to be confused with _execution context_ or _lexical context_)

``` js
function executionContext1 () {  
  console.log(this.a) // `this` is used in globally invoked function context  
}  
const obj1 = {  
  a: 1,  
  executionContext2() {console.log(this.a)} // `this` is used in method context  
};  
  
executionContext1() // execution context with `this` pointing to global object being created to execute this function  
executionContext2() // execution context with `this` pointing to `obj1` being created to execute this function
```

`this` contexts, determining its value:

- Global context (when this placed outside of functions or classes): this -> global object  
- Function context (when this placed inside the function)  
  - Globally invoked function: this -> global object  
  - Method: this -> object, on which method being called  
  - Constructor function: this -> instance object  
  - Arrow function: Exception. Do not have this. this -> inherited from outer function scope  
- Event handler context  
- Class context

### Global context

If `this` is used outside of functions or classes, it will be pointing to the global environment (`window` in a browser or `global` in NodeJS)

```js
console.log(this) // [object Window]
```

### Function context

`this` is determined by how the function is called, not how it is declared.  
Except for an _arrow function_, when a value of `this` is determined by where an arrow function is declared.

#### Globally invoked function

If a function is called In a global context, `this` refers to the _global object_.

```js
function printThis() {  
  console.log(this)  
}  
  
printThis() // Window // or undefined in strict mode
```

Notice that the value of `this` in a globally invoked function can be altered by the `"use strict"` directive.

#### Method

If a function is called as a method of an object, `this` will refer to that object (on the left side of the dot before a method). For `a.b.c.func()` `this` will be `c`

```js
const obj1 = {  
  a: 1,  
  log() {console.log(this.a)}  
};  
const obj2 = {  
  a: 2,  
  log: obj1.log  
};  
  
obj2.log(); // 2, because method is being called on `obj2`
```

#### Constructor Function

If `this` is used inside a constructor function, it points to the created instance of this constructor.

```js
function Person(name, birthYear) {  
  this.name = name // `this` will reference the instanse, so `name` will be added to `beatrix`  
  this.birthYear = birthYear // `this` will reference the instanse, so `birthYear` will be added to `beatrix`  
  
  this.describe = function() { // `describe()` will be added to `beatrix`  
    console.log(`${this.name} was born in ${this.birthYear}.`)   
    // `this` will be pointing to the object on which `describe` will be called (method context)  
  }  
}  
const beatrix = new Person('Beatrix', 2005)  
  
beatrix.describe() // "Beatrix was born in 2005."  
console.log(beatrix.name) // "Beatrix"
```

#### Arrow Function

Arrow functions are a special case, which makes `this` more tricky. They do not have their own `this` and inherit `this` value from the closest enclosing function scope. `this` value depends on how a function is declared, not how it is called (like with “normal” functions). In other words, `this` in arrow functions will point to the ‘owner’ of a function, despite where this function is being invoked. It means, that calling arrow functions as methods might result in an unexpected behavior:

```js
const obj = {  
  a: 1,  
  arrow: () => console.log(this.a), // there is no enclosing function, so this will point to global object  
  arrowNested:  
    function() {  
      return () => console.log(this.a) // will inherit the value of this from arrowNested() function, so it will point to `obj`  
  }  
}  
  
obj.arrow() // undefined  
obj.arrowNested()() // 1  
// value of `this` in arrow function is determined by where function being declared
```

In some cases, such a behavior of arrow functions might be handy, i.e. when used in event handlers.

### Event Handler

In the browser, there is a special `this` context for event handlers. In an event handler called by `addEventListener`, `this` will refer to the element, on which a listener is placed. In other words, `this` is pointing to `event.currentTarget`

```js
const button = document.createElement('button')  
button.textContent = 'Click me'  
document.body.append(button)  
  
button.addEventListener('click', function(event) {  
  console.log(this) // <button>Click me</button>  
})
```

Sometimes it is not convenient and _arrow functions_ being used to ‘preserve’ `this` value, no matter what ‘caller’ is:

```js
const person = {  
  name: "Beatrix",  
  sayHello: function() {  
    document.getElementById("myButton").addEventListener("click", () => {  
      console.log("Hello, " + this.name); // `this` inherited from `sayHello` and always will point to `person`, no matter where it will be invoked (arrow function context)  
    });  
  }  
};  
  
person.sayHello(); // "Hello, Beatrix"
```

### Class

When `this` is used inside a class, its value depends on what type of methods and field initializer it’s being used in:

- In public and private methods and field initializers `this` behaves like in constructor functions: pointing to an instance
- Static methods cannot be accessed via instance’s `this`. It must be called on class itself

```js
class C {  
  instanceField = this;  
  static staticField = this;  
}  
  
const instance = new C();  
  
console.log(instance.instanceField === instance); // true  
console.log(instance.staticField); // undefined because static methods cannot be accessed via instance's `this`   
console.log(C.staticField === C); // true
```

## Explicit Context of this

The value of `this` can be set manually by using special function methods. Note, that _Arrow functions_ do not have their own `this`, so these methods can’t be used with them.  
`.call()` and `.apply()` are used to call the function with a specified value of `this`:

```js
const obj1 = {  
	a: 1,  
	log() {console.log(this.a)}  
};  
const obj2 = {  
	a: 2,  
};  
  
obj1.log.apply(obj2); // 2, because `this` explicitely set to `obj2`  
obj1.log() // 1
```

`.bind()` is used to create a constant binding of `this` to a specified object:

```js
const obj1 = {  
	a: 1,  
	log() {console.log(this.a)}  
};  
const obj2 = {  
	a: 2,  
};  
const getObj2Var = obj1.log.bind(obj2);  
  
getObj2Var() // 2, because getObj2Var `this` binded to obj2
```

## Self-check

```js
const obj = {  
  a: 1,  
  b: function() {  
    console.log(this.a)  
  },  
  c: () => {  
    console.log(this.a)  
  },  
  d: function() {  
    return () => {  
      console.log(this.a);  
    }  
  }  
}  
  
// what the output will be?  
  
console.log(obj.a)  
  
obj.b()  
const b = obj.b  
b()  
obj.b.apply({a: 2})  
  
obj.c()  
obj.c.apply({a:2})  
  
obj.d()()  
obj.d.call({a:2})()  
obj.d().call({a:2})
```

### Answer

```js
console.log(obj.a)  // 1  
  
obj.b()             // 1           // method context  
const b = obj.b  
b()                 // undefined   // This is globally invoked function, not a method, so `this` is pointing to global object  
obj.b.apply({a: 2}) // 2  
  
obj.c()             // undefined   // Arrow function do not have outer function, so `this` reference global object  
obj.c.apply({a:2})  // undefined   // Arrow functions can't use .call() .apply() or .bind()  
  
obj.d()()           // 1           // first obj.d() being executed (method context)   
                                   // and returned arrow function. Then arrow function being executed in global context,   
                                   // but `this` in arrow function always points to the `this` of the encapsulating function.   
                                   // In this case `this` of `d()` pointing to `obj`, so `this` in arrow function   
                                   // will always reference `obj`, no matter where it called  
  
obj.d.call({a:2})() // 2           // same as above, but here `this` of `d()` was explicitely set   
obj.d().call({a:2}) // 1           // `call()` method was applied to arrow function, which is not making any sense.
```

### References

1. [this — JavaScript | MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this)
2. [Object methods, this](https://javascript.info/object-methods)

Happy coding! Feedback is appreciated.