DEV Community

Cover image for Let me explain to you what is `this`. (Javascript)
YCM Jason
YCM Jason

Posted on • Edited on

Let me explain to you what is `this`. (Javascript)

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.

it's over 9000!!!

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

Functions

Starting with functions. In this article, I would like to put functions into 3 different categories.

  1. Normal functions
  2. Arrow functions
  3. Bound functions

Normal functions

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('...');
Enter fullscreen mode Exit fullscreen mode

Arrow functions

Arrow functions are basically the ES6 arrow functions:

const magic = () => {
    ...
};
Enter fullscreen mode Exit fullscreen mode

Bound functions

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(...);
Enter fullscreen mode Exit fullscreen mode

Ways to call a function

Now let's say we have a function f (any category). There are 2 ways to call it.

  1. Implicit (direct) calls
  2. Explicit calls

Implicit (direct) calls

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();
Enter fullscreen mode Exit fullscreen mode

Explicit call

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(...);
Enter fullscreen mode Exit fullscreen mode

Quick recap

Let's do a quick recap, we have 3 categories of functions:

  1. Normal functions - created with function declaration/expression/constructor
  2. Arrow functions - () => {...}
  3. Bound functions - created with f.bind(...)

And 2 ways to call a function:

  1. Implicit (direct) calls - f() or obj.f()
  2. Explicit calls - f.call(...) or f.apply(...)

This means we have 6 different scenarios.

  1. Normal functions + Implicit (direct) calls
  2. Normal functions + Explicit calls
  3. Arrow functions + Implicit (direct) calls
  4. Arrow functions + Explicit calls
  5. Bound functions + Implicit (direct) calls
  6. Bound functions + Explicit calls

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:

  1. Normal functions + Implicit (direct) calls
  2. Normal functions + Explicit calls
  3. Arrow functions
  4. Bound functions

Procedure to find this


Below is the procedure to find the binding of this in function f:

Exercises!

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);
Enter fullscreen mode Exit fullscreen mode

QUESTION 1.a

Following flow chart, we want to find this in magic.

  1. Category of magic is normal function
  2. magic is called implicitly (directly)
  3. magic is called with magic()
  4. So this = undefined!!!

QUESTION 1.b

Following flow chart, we want to find this in cool.

  1. Category of cool is arrow function
  2. From QUESTION 1.b, we know magic's this is undefined
  3. cool's definer is magic
  4. So this = magic's this = undefined!

Lazy lecturer

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.

Answers

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

Note

  • There is no "bound arrow function". (() => {...}).bind(...) is still the original arrow function.
  • For implicit calling, only the shape (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`!!!
Enter fullscreen mode Exit fullscreen mode

Updates:

  • 16 July 2018: Thanks to @joshcheek for reminding me the correct binding of this of arrow functions!
  • 18 June 2018: Thanks to Yong for pointing out typo!

Top comments (28)

Collapse
 
elarcis profile image
Elarcis

this in the body of f is undefined!!! not obj!!!

Why does it happen though, that this code ran on Firefox (and I suppose, any other browser):

function f() { console.log(this); }

f();

const obj = {};
obj.fn = f;
obj.fn();
Enter fullscreen mode Exit fullscreen mode

prints respectively the Window object and the obj one?

Collapse
 
ycmjason profile image
YCM Jason • Edited

Great question. You are getting Window because you are not using 'use strict'.

Go to this link and the section called "Securing JavaScript" explains it.

developer.mozilla.org/en-US/docs/W...

Collapse
 
elarcis profile image
Elarcis

Oops. That actually explains a lot, as I used to get could not read property 'foo' of undefined a lot when passing my functions around as references, in strict mode.

Thank you for the link, I had forgot how much use strict mode changes the game!

Thread Thread
 
ycmjason profile image
YCM Jason • Edited

It makes code a little bit more reasonable.

Babel has implicit strict mode and u don't have to worry about forgetting to add it. :)

Collapse
 
gmartigny profile image
Guillaume Martigny

Without specific definition, this is the object wrapping the function. window is the fallback when can't be infer from any context.

Collapse
 
yahyaouimohamed profile image
yahyaoui-mohamed

To get undefined as result you have to use the strict mode.

Collapse
 
bgadrian profile image
Adrian B.G.

old man voice: And this my children is why you do not want to learn JS as your first language: you have too many (not so obvious) issues, you have to learn too many "JS" specific things, and less computer science/business problems. The result: you spend 90% debugging.

Ofc there are other 1000 reasons why you should learn JS as a first language, just saying :))

Collapse
 
ycmjason profile image
YCM Jason

You are absolutely right. I always suggest python as the first language. :)

Collapse
 
bgadrian profile image
Adrian B.G.

Is like the difference between jumping into a volcano and entering in a burning building, I think. Presumably the "new dev" use python to learn web dev, he/she also has to learn JS to make one, so is double the overkill.

I usually suggest something simpler like scratch.edu (for programming concepts, non-tech people, or kids), or Java (because the big ecosystem and the fact that OOP is more "natural" for non-tech people), or any strong typed language if you are studying CS, preferable with pointers.

Collapse
 
joshcheek profile image
Josh Cheek

This was really good :) In the flow chart, I don't think the arrow function's this is the caller's, I think it's the this at the time of construction. Eg:

$ node -p '({magic: function() { return () => this }}).magic()()'

The this will be bound to our magic object, where the arrow fn was created, not to global, where it was called.

Collapse
 
ycmjason profile image
YCM Jason

I have changed "caller" to "definer", which makes more sense.

Thank you so much! :)

Collapse
 
ycmjason profile image
YCM Jason

Oh yes you are right, let me update it later. Thanks for the shout! 😁😁😁

Collapse
 
vocab_king profile image
WhistlerIAM

Awesome explanation! The flowchart is by far the most unique thing on the web for this :p

Collapse
 
guitarkat profile image
Kat

What this are you referring to? 😁

Collapse
 
vocab_king profile image
WhistlerIAM

very droll

Collapse
 
ycmjason profile image
YCM Jason

😁😁 that is a huge compliment thanks!

Collapse
 
kepta profile image
Kushan Joshi • Edited

Since you tackled this so well. It would be great if you also added the almighty this inside an object constructor function to the flow chart.

To me more specific I am talking about

function Tree(name) {
  this.name = name;
}

var theTree = new Tree('Redwood');

I understand this is not exactly what your are addressing in your article, but new folks might frequently encounter this (oh the irony when talking about this) in these type of functions.

Cheers 🥂

Collapse
 
ycmjason profile image
YCM Jason

I could add this in the note. Not sure where to fit it in the flow chart haha.

Collapse
 
thorstenhirsch profile image
Thorsten Hirsch

20 years ago Perl's $_ was probably the most magical keyword in the programming world. :)

Collapse
 
thebouv profile image
Anthony Bouvier

And still easier to grok than JavaScript's this

Collapse
 
ycmjason profile image
YCM Jason

I am lucky I was just 3 years old at that time. 😌😌

Collapse
 
sekmo profile image
Francesco Mari

Nice article man! (But less gifs next time :-)

Collapse
 
guitarkat profile image
Kat

I love the gifs. Little distractions make for easier read on dry material. But I don't know how many is too many. 😋😅

Collapse
 
ycmjason profile image
YCM Jason

Haha! Ok, maybe a little less. I just went crazy and keep on adding after a few of them.

Collapse
 
chrisvasqm profile image
Christian Vasquez

Came for the memes. Stayed for the content.

Thanks for sharing this, Jason!

Collapse
 
ycmjason profile image
YCM Jason

Thanks! :) I am glad the memes worked out ok

Collapse
 
kidme profile image
kidme

Honestly really good article and explanation of the 'this' keyword after working with javascript for sometime now I still struggle with it. So thank you great work

Collapse
 
ycmjason profile image
YCM Jason

Awww thanks so much! :D