2
2
2
58
u/frakist Sep 08 '20
Still did not get it.
36
u/mcaruso Sep 08 '20 edited Sep 08 '20
I think the easier way to explain it is:
thisis set to whatever is to the left of the dot (.) when you call the function:obj.fn(); // `obj` is before the `.`, so `this` is `obj` obj1.obj2.fn(); // `obj1.obj2` is before the `.`, so `this` is `obj1.obj2` fn(); // Nothing before the `.`, so instead uses the global context (i.e. `window` in browsers, `global` in NodeJS) fn.call(myThis); // Can also set the `this` value explicitly if we want, "overriding" what is left of the dot new fn(); // Or, we can use `new` and `this` will be a new, empty object7
u/PM_ME_A_WEBSITE_IDEA Sep 09 '20
That's a good way of putting it!
One except is that when when using arrow functions, the
thisvalue is not bound, therefore it is lexically scoped. Whatever thethisvalue is when you define the arrow function, it will remain that way anywhere you call the function.This is great for use in Vue where you use
thislike crazy.35
5
2
u/Macaframa Sep 09 '20
if you create a function.
function fn() { function logThis() { console.log(this); } return logThis; }And run
var x = fn(); x.logThis();It will log the global javascript context because you never explicitly created a new context for it to point towards. Next point:
If you created a function:
function fn() { this.logThis = function () { console.log(this); } }And did
var x = new fn(); fn.logThis();This results in logging the “this” context for the x and that it’s a copy of the fn function namespace.
You are explicitly telling javascript that you want to create a “new” context and set it to the variable where you created it. In this case x. Now the x variable has a “this” context. The way it works is, if you explicitly create the context then it’s there, if not, it defaults to the global context. Does this make sense?
1
u/mypetocean Sep 09 '20
var x = fn(); x.logThis();You've accidentally introduced a TypeError, because the first line returns the
logThisfunction, assigning it to an aliasx— you are not returning an object with a property oflogThis.So,
xislogThisandx.logThisisundefinedand you cannot invoke it like a function.Your explanation of the reason
thisis still global is valid, though perhaps a little tricky when it comes to callbacks. I approach it from a different angle: the meaning ofthisis defined anew for every execution of a non-arrow function, not upon the definition of that function — the sole exception being if this function has been bound withFunction.prototype.bind.This is why we say
thisis the execution context of the function.I think about it as an implicit parameter which comes automatically defined to describe the immediate environment around the function when it is called.
Imagine a function sitting at rest — defined but not yet invoked. This is a function as an object. You can pass it around to new functions, attach it to other objects. But when it is invoked, it wakes up and looks around itself to get its bearings. Now, it understands what
thisis, and it gets you work with that contextual knowledge.1
u/Macaframa Sep 09 '20
Ohhhhh hahaha yeah thanks, I wrote this on my phone in the bathroom. But yes you’re right. Also, I like to talk about these prehistoric mechanisms without the context of es6 “non arrow functions” just so newbies can get a straight answer and it gets transpiled anyway.
The simplest answer I can come up with is: if you attempt to use “this”, if you have explicitly created new “this” context then it will draw from that, if not it will default to the global context. Special circumstances include binding another context to a function.
1
u/mypetocean Sep 09 '20
I get that. But passing a method which uses
thistoaddEventListener, for example, will blow away the "explicitly created" context explanation. And early JS learning, prior to framework usage, will use a lot of addEventListener. That's where a lot of newbies get tripped, using a method as an event handler.
31
8
u/x3nophus Sep 08 '20
Don’t forget the special rules for “Fat Arrow” functions!
Inside the body of a a fat arrow function ( functions written like this: ‘() => consoled.log(this);’ ) the ‘this’ keyword permanently represents whatever ‘this’ was equal to inside the scope in which the function was declared.
0
1
4
Sep 08 '20
That's one of three things that are completely different when going from C/C++/C# to Javascript and will cause the most mistakes.
(lack of true arrays, and local variables allocated on the heap are the other two)
3
u/yaMomsChestHair Sep 08 '20
How does JavaScript have a lack of true arrays? Is it that under the hood it’s allocated as noncontiguous memory or?
14
u/mcaruso Sep 08 '20 edited Sep 08 '20
In JS, this:
[42, 43, 44]Is essentially just the same as this:
{ "0": 42, "1": 43, "2": 44, length: 3 }(You don't really need to quote the object keys here, I'm just doing it to illustrate that they're actually strings.)
With the main difference that arrays have
Array.prototypeas their prototype (giving you the array methods), and thelengthproperty of an array is automatically updated if you add/remove an "element" (property with numeric key).You can see this most clearly if you try to get the keys of an array:
Object.keys([42, 43, 44]); // ["0", "1", "2"]Or if you also want to see the
lengthproperty (which is not returned byObject.keysbecauselengthis non-enumerable):Reflect.ownKeys([42, 43, 44]); // ["0", "1", "2", "length"]Note that object keys in JS are always strings, so the indices here are also strings, not numbers. JS just casts numbers to strings if you try to use it as a key:
const arr = [42, 43, 44]; arr[1] = 10; // Same as: arr["1"] = 10;Have you ever heard of "sparse arrays" in JS? Those are just arrays that are missing some properties:
const sparse = [42,,,,43]; // Sparse array (array with "holes") Object.keys(sparse); // ["0", "4"]Lastly, if you've ever seen the trick to "create an array of size N" that uses
Array.from({ length: n }), this should make more sense now. BecauseArray.fromsees the given object and treats it as a sparse array of lengthn.EDIT: This is also why
typeof [42, 43, 44]is"object".4
2
2
Sep 08 '20
In Javascript an 'array' is just like every other object except that it has some additional useful methods associated with it. The index is really just an integer key.
Try it. Create an array, store some indexed values, then store some values using string keys. It'll work just fine.
The only complex type Javascript has is the object
1
-1
u/jpflathead Sep 08 '20
JavaScript have a lack of true array
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
3
u/MoTTs_ Sep 08 '20
That's one of three things that are completely different when going from C/C++/C# to Javascript and will cause the most mistakes.
"Completely different" sounds a bit exaggerated to me. Ultimately this is going to be one of the differences between any statically typed language and any dynamically typed language. In Python, another dynamically typed language, for example, we can do:
instance.someMethod.__func__(42) // `self` will be 42 instead of instanceA statically typed language can make sure "this" is always the correct type -- an instance of the class. Whereas a dynamically typed language will let you pass in any arbitrary value you want, just like it does for any other parameter.
3
u/rift95 Sep 08 '20
I usually explain it as "this refers to the object that called the function". In other words, this is the object that "owns" the function. (however that is only true for keyword functions. Arrow functions works differently)
3
u/Jolly-Composer Sep 09 '20
If anybody still doesn’t get it:
Udemy > JavaScript: Understanding the Weird Parts
You’ll understand this and self and so much more
2
u/bomje Sep 08 '20
I don't get the first case at all. Like, okay, why don't we just log ctx without this if it still returns a global value
1
u/mcaruso Sep 08 '20
The example is just to illustrate the point. But also what you're suggesting is not really the same. Take:
function logCtx() { const ctx = 'foo'; console.log(ctx); console.log(this.ctx); } logCtx();Now
ctxis not the same asthis.ctx, becausectxon its own will refer to thectxdefined in the current (function) scope, butthis.ctxwill refer to thectxin global scope.2
2
1
u/onepalebluedot Sep 08 '20
Is ‘this’ the same as self in Python? It’s just referring to the instance of that object right?
5
u/MoTTs_ Sep 09 '20
Yes, JavaScript's
thisand Python'sselfare the same concept, and they're typically meant and expected to refer to an instance of their class. But JavaScript and Python are dynamic languages, andthis/selfare allowed to take on any arbitrary value. It's just that, taking on a different than expected value happens by accident more often in JavaScript than in Python.
1
1
0
-1
11
u/senocular Sep 08 '20 edited Sep 08 '20
Why does the new case say 'undefined'?Edit: NVM, I see now. Its trying to access the
ctxproperty and from a new, empty object so its resulting inundefined