
JavaScript - this
Planted:
Status: decay
Hits: 60
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
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.
index.js
function func() {this.a = 1;}func.call(func);console.log(func.a)console.log(globalThis.a)

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
function func3() {// call-stack = main -> func1 -> func2 -> func3// call-site = func2}function func2() {// call-stack = main -> func1 -> func2// call-site = func1func3();}function func1() {// call-stack = main -> func1// call-site = mainfunc2();}// call-stack = mainfunc1();
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.


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
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
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
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.
index.js
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
function func() {console.log(this.a);}// A var declared in the global scope will set a property on the global objectvar 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.
index.js
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.
index.js
const obj = {a: 1,func1() {console.log(this.a);},func2: () => {// As we are in an arrow function, 'this' = func2.// Setting func2.a = 2a = 2console.log(this.a);// Therefore, this.a = 2 (irrelevant where func2 gets called)}};// 'this' is setobj.func1()obj.func2()
Feedback
Have any feedback about this note or just want to comment on the state of the economy?