Original post: https://www.ycmjason.com/blog/2018/06/15.html
- this article assumes 'use strict' in all context
- this article also assumes some knowledge about functions but still a bit confused
this
in Javascript is the probably most magical keyword in the programming world. It's unpredictable nature has reached to an unprecedented level.
However, it is essential to understand it fully if you wish to become a master of Javascript. So let me try to explain you what is this
. (if it doesn't work, well, at least I tried.)
Starting with functions. In this article, I would like to put functions into 3 different categories.
I define normal functions as any function created with...
// function declaration
function magic() {
...
}
// function expression
const magic = function() {
...
};
// (or if you hate your life)
// function constructor
const magic = new Function('...');
Arrow functions are basically the ES6 arrow functions:
const magic = () => {
...
};
Bound functions can be created by calling Function.prototype.bind
on a normal functions.
// magic is created with function declaration/expression/constructor
const bound = magic.bind(...);
Now let's say we have a function f
(any category). There are 2 ways to call it.
Implicit (direct) calls are boring:
/* f is defined */
// direct call
f();
// or attach it to an object and call it
const obj = {};
obj.fn = f;
obj.fn();
Explicit calls are more interesting. You can call your function with Function.prototype.call
or Function.prototype.apply
.
/* f is defined */
// Function.prototype.call
f.call(...);
// Function.prototype.apply
f.apply(...);
Let's do a quick recap, we have 3 categories of functions:
() => {...}
f.bind(...)
And 2 ways to call a function:
f()
or obj.f()
f.call(...)
or f.apply(...)
This means we have 6 different scenarios.
Don't panic, it is not that scary.
In fact, arrow functions and bound functions do not care about implicit/explicit calls. So this reduces down to only 4 scenarios:
this
Below is the procedure to find the binding of this
in function f
:
Given magic
defined as follows:
'use strict';
const magic = function() {
// a. what is `this`?
console.log(this);
const cool = () => {
// b. what is `this`?
console.log(this);
};
cool();
};
// QUESTION 1
magic();
// QUESTION 2
const apple = { name: 'apple' };
apple.magic = magic;
apple.magic();
// QUESTION 3
const orange = { name: 'orange' };
magic.call(orange);
Following flow chart, we want to find this
in magic
.
magic
is normal functionmagic
is called implicitly (directly)magic
is called with magic()
this
= undefined
!!!Following flow chart, we want to find this
in cool
.
cool
is arrow functionmagic
's this
is undefined
cool
's definer is magic
this
= magic
's this
= undefined
!The remaining questions, QUESTION 2.a, 2.b, 3.a and 3.b, are trivial with my flow chart. So I will leave them as an exercise for you all.
https://repl.it/@ycmjason/What-is-this
Click run and you will see the answer in order (1.a, 1.b, 2.a, 2.b, 3.a, 3.b).
(() => {...}).bind(...)
is still the original arrow function.f()
or obj.f()
) matter. It doesn't matter where f
comes from. Consider the following code:const f = obj.f; // obj.f is a normal function
f(); // `this` in the body of `f` is `undefined`!!! not `obj`!!!
Updates:
this
of arrow functions!