JavaScript - this
Planted:
Status: decay
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
.
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 and defines what this
is bound to.
Console
function func() { this.a = 1; } func.call(func); console.log(func.a) console.log(globalThis.a)

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


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?
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?
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?
Console
function func() { console.log(this.a); } const obj = { a: 1 }; func.call(obj);
call(..)
invokes a function and 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.
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.
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.

No Bridge
this
does not refer to a function's scope.
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
and 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.
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.
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()