What is `this` ?
- a method is simply a function that has an explicit receiver
- does not have an explicit receiver (the global object is the implicit receiver)
So we think, ok, that’s easy. The method is defined as a property on an object. The function is declared in the global space. Done.
Well not really….
See, a method or a function can be the same exact piece of code in memory, how it is invoked is what makes the difference whether it is a method or function, not how it is defined.
line 11— points the global variable ‘globalIntroduce’ to the same function property ‘introduce’ of the person object
line 13 — prints ‘Hello, my name is undefined’; let’s talk about why
Now, is a good time to introduce `this`!
Notice on line-4 of the above snippet where we make a reference to
this.name . The keyword
Here is the rule….
- if it’s a function invocation (no explicit receiver) then the current execution context, referenced in code by the
thiskeyword, is the global object(
windowin the browser or
globalin non-browser environments).
- if it’s a method invocation (has explicit receiver) then the current execution context, referenced in code by the
thiskeyword, is the object in which it is defined (the calling object).
If we refer back to the previous snippet, we see that the call to
globalIntroduce()on line-14 prints undefined because of line-4 inside the body of the function. It makes a reference to
this.name, as we see clearly,
globalIntroduce()is a function invocation meaning it’s
thisvalue is a reference to the global
windowobject. So the
thisreference is saying
“lookup the property ‘name’ on the current execution context (
window), concatenate it to the string ‘Hello, my name is ‘ and print it out”.
When it fails to find a property called
nameon the global object, it returns undefined as expected.
Let’s look at that same code with one minor change.
Whoa! What happend here?? Notice on line 8 we defined a variable
So we see that variables defined in the global space are actually properties on the global object. There are some nuances to be explored here, including the difference between declared and undeclared variables and how they show up differently in regard to the global object, but those topics are outside of the realm of this blog, if you don’t already understand it, I highly recommend doing some digging on this subject.
Ok, so we understand method invocation vs function invocation, as well as the fact that the
apply(), call(), bind()…..
Function.prototype.apply(context, [array, of, arguments])
Function.prototype.call(context, comma, separated, args)
call() and bind() are very similar, in-fact, their only difference is the way they accept extra arguments that are passed along to the receiver function. They invoke any function they are chained to while accepting an explicit context to be set as the
this value during execution of the calling function, any extra arguments passed in (as an array in the case of apply(), and as comma separated args in the case of call()), are passed along to the calling function.
Function.prototype.bind(context, extra, args)
bind() is slightly different than the first two, instead of invoking the calling function, it returns a new function that’s a copy of the caller, except with the passed in context permanently bound to the resulting function, and any args passed in will be prepended to the arguments passed in upon invocation of the resulting function.
Let’s look at all this in some code…
call() , and
apply(), methods are very useful when building objects in actual programs. There are many cases when building objects where nested functions lose the context of the outer containing object and these methods are a life-saver when trying to make your code function as expected. I’ll explore these cases in a later topic on dealing with context loss.
For now, let’s just be glad we have a good grasp on what