See the Pen thecodelog.com - JS This 1 by Deano (@deangilewicz) on CodePen.
Function context:
Inside of a function, the value of this depends on how the function is called. There are four ways to call a function that produces a different result for the context of this keyword.
1. Default binding rule (simple call):
If none of the other rules apply then apply global object to this keyword (non strict) or undefined (strict mode).
The following code is not in strict mode, and because the value of this is not set by the call, this will default to the global object:
See the Pen thecodelog.com - JS This 2 by Deano (@deangilewicz) on CodePen.
In strict mode, the value of this remains at whatever it was set to when entering the execution context, so, in the following case, this will default to undefined:
See the Pen thecodelog.com - JS This 3 by Deano (@deangilewicz) on CodePen.
2. Implicit binding (call site has a context object)
If at the call site there is a context object then use context object as this keyword. When a function is called as a method of an object, its this is set to the object the method is called on. Here, we define the function inline as the fn member during the definition of obj.
See the Pen thecodelog.com - JS This 4 by Deano (@deangilewicz) on CodePen.
However, we can also define the function first and later attach it to obj.fn, since it only matters that the function was invoked from the fn member of obj.
See the Pen thecodelog.com - JS This 5 by Deano (@deangilewicz) on CodePen.
The this binding is only affected by the most immediate member reference. When we invoke the function, we call it as a method myFn of the object obj.b. This time during execution, this inside the function will refer to obj.b. The fact that the object is itself a member of obj has no consequence; the most immediate reference is all that matters.
See the Pen thecodelog.com - JS This 6 by Deano (@deangilewicz) on CodePen.
If the method is on an object’s prototype chain, this refers to the object the method was called on, as if the method was on the object.
See the Pen thecodelog.com - JS This 7 by Deano (@deangilewicz) on CodePen.
The object assigned to obj2 doesn’t have its own myFn method so it inherits it from its prototype. It doesn’t matter that the lookup for myFn eventually finds a member with that name on obj; the lookup began as a reference to obj2.myFn, so this inside the function takes the value of the object referred to as obj2. That is, since myFn is called as a method of obj2, its this refers to obj2.
Beware of calling a function in the following way since the implicitly is lost.
See the Pen thecodelog.com - JS This 8 by Deano (@deangilewicz) on CodePen.
Above, thing() is invoked in the global context so this refers to the ‘a’ property on the window, which has a value of “hello world”.
3. Explicit binding (call, apply, or bind)
Both call and apply will determine the context of this keyword and can be used to pass the value of this from one context to another.
See the Pen thecodelog.com - JS This 9 by Deano (@deangilewicz) on CodePen.
With call and apply, if the value passed as this is not an object, an attempt will be made to convert it to an object using the internal toObject operation.
See the Pen thecodelog.com - JS This 10 by Deano (@deangilewicz) on CodePen.
Bind creates a new function with the same body and scope as the function, but where this occurs in the original function, in the new function it is permanently bound to the first argument of bind, regardless of how the function is being used.
See the Pen thecodelog.com - JS This 11 by Deano (@deangilewicz) on CodePen.
4. “New” keyword (constructor)
A constructor is just a regular function that is called with the new keyword in front of it. When a function is used in this way its this is bound to the new object being constructed.
There are four steps that occur when the new object is being constructed:
- A brand new empty object is created out of thin air
- This brand new created object is linked to another object
- This brand new created object is used as the this context for purpose of function call (passes it in as this keyword)
- If function in question does not return an object then will assume it is supposed to return this keyword (the newly created object)
See the Pen thecodelog.com - JS This 12 by Deano (@deangilewicz) on CodePen.
DOM event handler:
When a function is used as an event handler, its this is set to the element the event fired on.
See the Pen thecodelog.com - JS This 13 by Deano (@deangilewicz) on CodePen.
Binding Exceptions:
1. Arrow Functions
With arrow functions, this is set to that of the outer execution context (lexically). When used in the global context, this will be set to the global object.
See the Pen thecodelog.com - JS This 14 by Deano (@deangilewicz) on CodePen.
It doesn’t matter how myFn is called, it’s this will stay as the global object. This also holds if it’s called as a method of an object, which would usually set its this to the object.
See the Pen thecodelog.com - JS This 15 by Deano (@deangilewicz) on CodePen.
2. Passing null or undefined
If you pass null or undefined as a this binding parameter to call, apply, or bind, those values are effectively ignored, and instead the default binding rule applies to the invocation.
See the Pen thecodelog.com - JS This 16 by Deano (@deangilewicz) on CodePen.
This approach can be used in a useful way even with strict mode.
See the Pen thecodelog.com - JS This 17 by Deano (@deangilewicz) on CodePen.
Instead of passing null as this context it can be safer to pass an empty object instead. The easiest way to set an object up as totally empty is Object.create(null). Object.create(null) is similar to {}, but without the delegation to Object.prototype, so it’s more “empty” than just {}.
See the Pen thecodelog.com - JS This 18 by Deano (@deangilewicz) on CodePen.
In summary, there are 4 steps to order of precedence:
1. Is the function called with new (new binding)? If so, this is the newly constructed object.
var thing = new myFn();
2. Is the function called with call, apply, or bind (explicit binding). If so, this is the explicitly specified object.
var thing = myFn.call(myObj);
3. Is the function called with a context object (implicit binding). If so, this is the context object.
var thing = myObj.myFn();
4. Otherwise, default binding will occur. If in strict mode, then this will be undefined, otherwise pick the global object.
var thing = myFn();