What is “this” in Javascript — especially, when you use bind( ), arrow function and regular function?
this refers to its closest object.
If this
is called in a global scope, then this
refers to window
object in a browser or global
object in Node.
function checkThis() {
return this;
}// In a browser:
checkThis() === window; // true // In Node:
checkThis() === global; // true
But what other things that could be inside
this
?The answer is, well … whatever the object is.
this
is but an alias to the actual object. See below, this
is equivalent to user.
let user = {
name: "Maya",
age: 30, callMe() {
alert(this.name);
alert(user.name);
}};user.callMe(); // will output "Maya", and then "Maya" again
That’s it?
Wait, there is more!
this
is defined or evaluated during run-time. The moment you create or write this
, this
is just a concept or a keyword in the ocean of your codebase (that you expect to work and mean something, of course). But only when the function runs, this
will turn into an object (or undefined
, when there is no object in its outer scope and when the code is set to be in a strict
mode).
let human = { name: "Maya" };
let dog = { name: "Pillow" };function sayHi() {
alert( this.name );
}// assign the function into two objects
human.sayHi = sayHi;
dog.sayHi = sayHi;
When we call sayHi()
on two different objects (human
and dog
), this
has different objects each time.
this
inside the following function is the object “before the dot”
human.sayHi(); // Maya (this == human)
this
inside the following function call is the object “before the opening bracket”
dog['sayHi'](); // Pillow (this == dog)
*Both function call styles work just the same.
So the meaning of
this
just relies on the scope, its closest object and the run-time of our function then?Not necessarily. Especially if that is not what you want.
We can actually decide what this
should be!
How?
We can tie our this
to whatever object we pass in to our bind()
.
Let’s see two examples of similar code with different names addThis()
and noThis()
, both run console.log(this);
function addThis() {
console.log(this) // 'this' = "hello" because it is bound to "hello"
}function noThis() {
console.log(this); // 'this' = window object
}let runMe = addThis.bind("hello"); // ties "hello" to addThisrunMe(); // executes addThis and returns "hello" noThis(); // executes noThis and returns a window object
But what about a function that lives inside a function that is already bound to an object?
Will that inner function inherit the bound object of its parent’s function?
The answers are : YES AND NO.
Yes, if the inner function is an arrow function.
Because this type of function does not have its own this
, but will latch on to any object that its parent is bound to (a window
object if the arrow lives in the global scope).
No, if the inner function is a function that uses function keyword.
Because, this type of function, will lose its binding / object context and back to be to tied to the window
object again.
function parentFunc() { console.log(this) // 'this' = "hello"
childFuncArrow = () => {
console.log(this); // 'this' = "hello"
}; childFuncArrow();
function childFuncNormal() {
console.log(this); // 'this' = the window object - oh no!
} childFuncNormal();
}let runMe = parentFunc.bind("hello"); runMe(); // execute parentFunc which outputs "hello", "hello", Window object
Even if we don’t use bind()
, inner arrow function will always take its this
from the nearest object - which in this case is bound to the arrow function by its normal function parent, the twoFunctions()
. But inner normal function will lose its context.
The example below, shows an arrow function’s this
as the human object (its direct parent’s this
) and the normal function will return undefined
.
let human = { name: "Maya",
twoFunctions() { console.log(this.name); // output "Maya" let arrow = () => console.log(this.name); // output "Maya" arrow();
function notArrow() {
console.log(this.name); // output "undefined" - because it tries to call window.name
}
notArrow();
},
}
human.twoFunctions(); // Will output "Maya", "Maya" and "undefined"