Last active
April 28, 2023 10:31
-
-
Save ajitid/fc7d5b6129cbf30ccd6aff954e85e462 to your computer and use it in GitHub Desktop.
Understanding `this`
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
// using strict mode as `this` behavior can change in a non-strict JS https://egghead.io/lessons/javascript-this-in-function-calls | |
// ESM files use `"use strict";` by default | |
// ------------- | |
// Let's see what top level `this` is in different environments | |
/* | |
in browsers | |
this === globalThis === window | |
*/ | |
/* | |
in ESM (files with .mjs extension or type=module) | |
this === undefined | |
globalThis === global // containing setTimeout, clearInterval... | |
*/ | |
// console.log(this); | |
// console.log(globalThis === global); | |
/* | |
in CJS | |
this === module.exports | |
globalThis === global // containing setTimeout, clearInterval... | |
*/ | |
// console.log(this === module.exports); // true | |
// module.exports = { xx: "yy" }; // reassignment happen | |
// console.log(this === module.exports); // false, as `this` still holds original module.exports obj. | |
/* | |
Because assigning to `this` is not allowed like: | |
this = {"something": "new"} | |
So in ESM we cannot change `this` from undefined. | |
But in CJS `this` refers to an object so we do something like: | |
*/ | |
module.exports["global"] = "value"; | |
/* so lets use CJS for this file. */ | |
// --------------- | |
// add a `/` at the start of the next line to uncomment the block | |
/* | |
{ | |
const a = { | |
v: 4, | |
fn() { | |
return this; | |
}, | |
afn: () => { | |
return this; | |
}, | |
}; | |
console.log(a.fn()); | |
console.log(a.afn()); // an arrow fn gives outer scope's `this` | |
console.log("--"); | |
// rebinding helps to restore `this` ctx | |
let fn = a.fn; | |
console.log(fn()); | |
fn = fn.bind(a); | |
console.log(fn()); | |
console.log("--"); | |
// bind doesn't work with arrow fns | |
fn = a.afn; | |
console.log(fn()); | |
fn = fn.bind(a); | |
console.log(fn()); | |
} | |
//*/ | |
/* | |
{ | |
// arrow fn behavior in classes https://www.youtube.com/watch?v=7bsA6Poxvy4 | |
// the code below is unrelated so do watch the video first: | |
// With this code and the code written above, all I'm trying to convey is: | |
// - An arrow function uses closure to capture `this`, while to a normal func we bind a `this`. | |
// - In an object, an arrow fn will capture `this` not from the object, but from its outer scope, | |
// on the other hand an arrow func defined in class or function() will capture class or function()'s this | |
const l = console.log; | |
const o = { | |
val: 3, | |
fn() { | |
l(this); | |
}, | |
afn: () => { | |
l(this); | |
}, | |
}; | |
o.fn(); | |
o.afn(); | |
console.log("--"); | |
class C { | |
fn() { | |
l(this); | |
} | |
afn = () => { | |
l(this); | |
}; | |
} | |
const c = new C(); | |
c.fn(); | |
c.afn(); | |
console.log("--"); | |
// `class` is a syntactic sugar on a constructor function that can create instances. | |
// So this will behave the same as class, | |
// (Only exception being here is that `fn()` is assigned on the instance, not on the prototype, | |
// which we could've emulated by doing `this.__proto__.fn = function() {...}` if we wanted to) | |
function FC() { | |
this.fn = function () { | |
l(this); | |
}; | |
this.afn = () => { | |
l(this); | |
}; | |
} | |
const fc = new FC(); | |
fc.fn(); | |
fc.afn(); | |
} | |
//*/ | |
/* | |
{ | |
// The last thing I want to mention is function called with no `this` context will give `undefined`. | |
// This behavior is similar to the case when you do `const separatefn = classInstance.fn; separatefn();` and `this` inside `separatefn` becomes `undefined`. | |
function fn() { | |
console.log(this); | |
} | |
fn(); | |
// again looping back to the video mentioned at the very top of this file: ^ above fn call will give undefined only if strict mode is enabled | |
} | |
//*/ | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Once you understand all that, check out this specific question https://javascript.info/object-methods#using-this-in-object-literal and click on the solution & go to its bottom to see the right answer.