Note : Most of the content is from Kyle Simpson’s book (You Don’t Know JS- this & Object Prototypes) I have modified some things ans well as deleted some to ease my understanding
What’s mystery of this
We said earlier that this is not an author-time binding but a run time
binding. It is contextual based on the conditions of the function’s invocation. this binding has nothing to do with where a function is declared, but has instead everything to do with the manner in which
the function is called. When a function is invoked, an activation record, otherwise known as an execution context, is created. This record contains information about where the function was called from (the call-stack), how the function was invoked, what parameters were passed, etc. One of the properties of this record is the this reference, which will be used for the duration of that function’s execution.
- Default binding
this rule is the default catch-all rule when none of the other rules apply. Consider following code snippet
The first thing to note, if you were not already aware, is that variables declared in the global scope, as var a = 2 is, are synonymous with global-object properties of the same name. They’re not copies of each other, they are each other. Think of it as two sides of the same coin.
Second, we see that when foo() is called, this.a resolves to our global variable a. Why? Because in this case, the default binding for this applies to the function call, and so points this at the global object.
If strict mode is in effect, the global object is not eligible for the
default binding, so the this is instead set to undefined:
- Implicit Binding
at the point that foo() is called, it’s preceeded by an object reference to obj. When there is a context object for a function reference, the implicit binding rule says that it’s that object that should be used for the function call’s this binding. Because obj is the this for the foo() call, this.a is synonymous with obj.a. Only the top/last level of an object property reference chain matters to the call-site.
One of the most common frustrations that this binding creates is
when an implicitly bound function loses that binding, which usually
means it falls back to the default binding of either the global object or undefined, depending on strict mode.
- Explicit Binding
With implicit binding, as we just saw, we had to mutate the object in
question to include a reference on itself to the function, and use this property function reference to indirectly (implicitly) bind this to the object. But, what if you want to force a function call to use a particular object for the this binding, without putting a property function reference on the object?
“All” functions in the language have some utilities available to them
(via their [[Prototype]]—more on that later), which can be useful
for this task. Specifically, functions have call(..) and apply(..)
Invoking foo with explicit binding by foo.call(..) allows us to force
its this to be obj. With respect to this binding, call(..) and apply(..) are identical. The difference is that apply lets you invoke the function with arguments as an array; call requires the parameters be listed explicitly. A useful mnemonic is “A for array and C for comma.”
We create a function bar() which, internally, manually calls foo.call(obj), thereby forcibly invoking foo with obj binding for this. No matter how you later invoke the function bar, it will always manually invoke foo with obj. This binding is both explicit and strong, so we call it hard binding. Since hard binding is such a common pattern, it’s provided with a builtin utility as of ES5, Function.prototype.bind. The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
- new Binding
When a function is invoked with new in front of it, otherwise known
as a constructor call, the following things are done automatically:
1. A brand new object is created (aka constructed) out of thin air.
2. The newly constructed object is [[Prototype]]-linked.
3. The newly constructed object is set as the this binding for that
4. Unless the function returns its own alternate object, the newinvoked function call will automatically return the newly constructed object.
By calling foo(..) with new in front of it, we’ve constructed a new
object and set that new object as the this for the call of foo(..). So
new is the final way that a function call’s this can be bound. We’ll call this new binding.