1) Whatâs this
ďź
The key word this
is a current module or current functionâs context, it automatically resolves to an object or scope depending on the context at which was defined.
Letâs consider a similar scenario in word use in English, e.g run
. Run is a single word that could mean many different things depending on the context.
- âI will run homeâ â means to move quickly on foot
- âShe ran the 1500mâ â means to run in a race
- âHe is running for presidentâ â means vying for an official position
- âThe app is runningâ â means the software application is still open and active
- âGo for a runâ â means running as a form of exercise
So, we could visit different context when we use different functions, which means we use different this
to call the same function, it will return different result.
1.1) this
context?
When used in a function, the this keyword simply points to an object to which it is bound. It answers the question of where it should get some value or data from:
// A function with a "this" reference
function alert() {
console.log(this.name + ' is calling');
}
In the function above, the this keyword is referring to an object to which it is bound so it gets the ânameâ property from there.
But how do you know which object the function is bound to? How do you find out what this is referring to?
To do so, we need to take a detailed look at how functions are bound to objects.
Before we process to next part, we should tell regular function
and arrow function
apart, which has some difference when using this
.
2) The Binding RULE of this
in the regular function
There are generally four kinds of bindings:
- Default Binding
- Implicit Binding
- Explicit Binding
- Constructor Call Binding
FIRST PRINCIPLE
: If itâs a regular function, the this
reference is up to the context when
the function was CALLED
.
2.1) Default Binding
- Non-strict mode: If a function is a standalone, unattached function, then the
this
reference the function housing resolves to the global scope (Browser is theWindow
, and NodeJS is theGlobal
). - Strict mode: The
this
reference is set toundefined
, cause that thethis
is not allowed to resolve to global in the strict mode.
Let take a look at this:
var name = 'pero';
var hello = {
name: 'wong',
foo: function () {
// 'use strict'
console.log(this.name);
}
}
var bar = hello.foo;
bar(); // there
In the Non-strict mode, it will output pero. Because there is window.bar()
actually, and itâs this
resolves to the global.
And in the strict mode, it will throw error like âTypeError: undefined is not an object (evaluating âthis.nameâ)â
2.2) Implicit Binding
Another scenario to look out for is whether the function is attached to an object (its context) at the call site.
According to the binding rule in JavaScript, a function can use an object as its context only if that object is bound to it at the call site. This form of binding is known as implicit binding
.
e.g. The sayHi is attached to the person object, when the sayHi function was called, this
is implicitly bound to person. So the output is âHello, wongâ.
var name = 'pero';
var person = {
name: 'wong',
sayHi: sayHi
};
function sayHi() {
console.log('Hello,', this.name); // Hello, wong
}
person.sayHi();
Letâs look at another example:
function alert() {
console.log(this.age + ' years old');
}
const myObj = {
age: 22,
alert: alert,
nestedObj: {
age: 26,
alert: alert
}
}
myObj.alert(); // `this` is bound to `myObj` -- 22 years old
myObj.nestedObj.alert(); // `this` is bound to `nestedObj` -- 26 years old
Here, because alert is ultimately being called from nestedObj, this is implicitly bound to nestedObj instead of myObj.
An easy way to figure out which object this is implicitly bound to is to look at which object is to the left of the dot (.)
Letâs consider another case:
var name = 'pero';
var person = {
name: 'wong',
sayHi: sayHi
};
function sayHi() {
console.log(this); // { name: 'wong', sayHi: Fn }
setTimeout(function () {
console.log('Hello,', this.name); // Hello, pero
});
}
person.sayHi();
Q: why this
refers to global?
A: Do you remember the FIRST PRINCIPLE
? The this
reference is up to the context when
the function was CALLED. So when the second console.log was execute, itâs context is not in the person.sayHi, itâs in the global.
2.3) Explicit Binding
If we want to force a function to use an object as its context without putting a property function reference on the object, how could we do?
There are two utilities: call
, apply
Along with a couple other set of utility functions, these two utilities are available to all functions in JavaScript via the [[Prototype]] mechanism.
fun.call(this, arg1, arg2, ...)
fun.apply(this, [arg1, arg2, ...])
To explicitly bind a function call to a context, you simply have to invoke the call() on that function and pass in the context object as parameter. e.g.
var person = {
name: 'pero'
}
function changeWork(company, work) {
this.company = company;
this.work = work;
}
changeWork.call(person, 'Google', 'UE');
console.log(person.work); // UE
changeWork.apply(person, ['Amazon', 'SE']);
console.log(person.work); // SE
Tips: If we pass primitive types (number, string, boolean) when using call and apply, this
will be convert to object.
function getThisType() {
console.log('this is ', this, typeof this);
}
getThisType.call(1); // this is Number {1} object
getThisType.apply('pero'); // this is String {'pero'} object
getThisType.call(true); // this is Boolean {true} object
2.4) Constructor Call Binding
When a function is invoked with the new keyword in front of it, otherwise known as a constructor call, the following things occur:
- A brand new object is created (or constructed)
- The newly constructed objectâs proto is [[Prototype]]-linked to the function that constructed it
- The newly constructed object is set as the this binding for that function call
- Execute the the constructor function
- Return the newly constructed object
function study(name) {
this.name = name
}
const studyDay = new study('pero')
console.log(studyDay) // { name: 'pero' }
console.log(studyDay.name) // pero
3) The difference of this
in the arrow function
The 2) we make sense the this
reference of the regular function, and what the difference between regular function and arrow function?
Remember the first principle of the this reference of the regular function?
In the arrow function, the FIRST PRINCIPLE
is known as: If itâs a arrow function, the this
reference is up to the context where
the function is DEFINED
.
We know that arrow function donât have itself this
, so the this
reference is determined by where the arrow function.
Do you remember the oddly case aforementioned?
var name = 'pero';
var person = {
name: 'wong',
sayHi: sayHi
};
function sayHi() {
console.log(this); // { name: 'wong', sayHi: Fn }
- setTimeout(function () {- console.log('Hello,', this.name); // Hello, pero- });+ setTimeout(() => {
+ console.log('Hello,', this.name); // Hello, wong
+ });
}
person.sayHi();
And what will happened if we change the regular function to arrow function in the setTimeout.
Yes, it will output âhello, wongâ.
If you have any question about this article, you can reach me on Twitter.
Be sure to check out my blog for more JavaScript and programming related content.