The word 'this'

JavaScript - this

Planted

Status: seed

When a function is invoked, it creates an execution context containing:

  • where the function was called (the call-stack),
  • how the function was called,
  • what parameters were passed,
  • the this reference. this is a keyword representing a binding.
  • ...

Below, func is called in the global scope. When that is executed, this is bound to the global object. When this.a = 1 is executed, it will result in globalThis.a = 1.

/index.js

Console

function func() {
this.a = 1;
}
func();
console.log(func.a)
console.log(globalThis.a)

If the intention was to add an a property to the func object, .call(..) could be used. It calls a function & defines what this is bound to.

/index.js

Console

function func() {
this.a = 1;
}
func.call(func);
console.log(func.a)
console.log(globalThis.a)
Source
A map of Middle Earth.

Determine this - Call-Site

If you need to find what this is bound to at some point in your code, you 1st need to find the call-site. The location where a function is called. It can be determined by looking at the call-stack.

/index.js

Console

function func3() {
// call-stack = main -> func1 -> func2 -> func3
// call-site = func2
}
function func2() {
// call-stack = main -> func1 -> func2
// call-site = func1
func3();
}
function func1() {
// call-stack = main -> func1
// call-site = main
func2();
}
// call-stack = main
func1();

The call-stack can be viewed in the browser dev tools. Set a breakpoint & refresh the page, the debugger will pause at this line. It will display the current call-stack. The 2nd item from the top will be the call-site.

A screenshot of the browser console with the call-site underlined.
Judge Dredd

Determine this - Rules

Base on the call-site, ask these questions in order. Stop when the 1st rule applies.

1. Is the function called with a new binding?

/index.js

Console

function func(a) {
this.a = a;
}
const myVar = new func(1);
console.log(myVar.a)

When a function is invoked with new in front of it (a constructor call):

  1. a new object is created
  2. the object is [[Prototype]]-linked
  3. the object is set as the this binding for that function call
  4. unless the function returns its own alternate object, the new-invoked function call will automatically return the newly constructed object.

2. Has bind(..) been used?

/index.js

Console

function func1() {
console.log(this.a);
}
const obj = {
a: 1
};
const func2 = func1.bind(obj)
func2()

bind(..) returns a new function that is hard-coded to call the original function with the specified this.

3. Is call(..) or apply(..) used?

/index.js

Console

function func() {
console.log(this.a);
}
const obj = {
a: 1
};
func.call(obj);

call(..) invokes a function & defines what this should be a bound to. apply(..) would have the same result.

4. Does the call-site have a context object?

this is that context object.

/index.js

Console

function func() {
console.log(this.a);
}
const obj = {
a: 1,
func
};
obj.func();

The call-site uses obj's context to reference the function. At the point that func is called, it's preceded by an object reference to obj. This is common when using browser API functions like setTimeout(() => { .. }, 1000). setTimeout is actually window.setTimeout. Therefore, this within the anonymous function is window.

5. undefined in strict mode, global object otherwise

The catch-all rule when none of the other rules apply.

/index.js

Console

function func() {
console.log(this.a);
}
// A var declared in the global scope will set a property on the global object
var a = 1;
func();

When func is called, this is bound to the global object.

Source
A sphere moving through a wormhole wireframe.

No Bridge

this does not refer to a function's scope.

JS

Console

function func1() {
const a = 1;
this.func2();
}
function func2() {
console.log(this.a);
}
func1();

The above code is attempting to use this to create a bridge between the scopes of func1 & func2. So func2 can access a. No such bridge is possible. You can't use a this reference to look something up in a scope.

A JavaScript arrow function.

Arrow-Functions

Instead of the 4 standard binding rules, an arrow-function, () => { .. } will adopt the this binding from its enclosing function call. Set when the function is created, not to the environment in which the function is called.

/index.js

Console

const obj = {
a: 1,
func1() {
console.log(this.a);
},
func2: () => {
// As we are in an arrow function, 'this' = func2.
// Setting func2.a = 2
a = 2
console.log(this.a);
// Therefore, this.a = 2 (irrelevant where func2 gets called)
}
};
// 'this' is set
obj.func1()
obj.func2()

Where to Next?