Understanding JavaScript’s ‘this’

JavaScript functions are objects and so can have properties. When a function executes it gets a this property. The value of this will refer to the object that called the function.

Global scope

When running code in the browser, window is the global object. The value of this will be the window object when this is referenced in the global scope.

We can see in the code that window and this are interchangeable.

Function scope

When referencing this within a function, the value of this is not set until the function is called.

Here this is referenced within a function but because the function is called in the global scope the value of this is the window object.

The same applies when printName() is called.

When using strict mode the value of this in global functions will be undefined.

Object method

Remember that the value of this is not set until the function is called.

Here this refers to myObject because it called printThis().

myObject calls printName() so the value of this is myObject and this.name will evaluate to ‘My Object’.

Here we define the function printName() independent of myObject and attached a reference to the myObject property printName. Again, myObject calls printName so the value of this is myObject and this.name evaluates to ‘My Object’.

This example has nested objects and we call printName() by first going through outerObject to call innerObject.printName(). Here the value of this is innerObject because it is the direct caller of printName(). It does not matter that we started by calling outerObject.

Prototypes

Here myObject calls both printName() and printThis() which means that the value of this for both is myObject. myObject does not have a property named name, it is inherited from the prototype. Note that this does not affect the value of this. this is still set to the object that called the function.

Constructor

We use the function MyConstructor as a constructor using the new keyword. In this case this will point at the new object being constructed, myObject.

Closures

In this example this inside the anonymous function no longer refers to myObject so this.name will be undefined.

One solution is to store a reference to this in a variable and use the variable instead. Later we will see how this can be fixed using bind.

forEach can be passed a second parameter which allows us to specify what should be used for this.

Now this.name will evaluate to ‘My Object’ because we have passed in this as the second parameter to forEach.

Here again this inside innerFunction no longer refers to myObject because myObject is not the direct caller of innerFunction().

We can fix it by storing a reference to this in a variable. Now it prints ‘My Object’ as expected.

This behaves exactly as the last example. We just defined outerFunction outside of myObject.

Event handler

this within the anonymous function does not refer to myObject, it will be set to the element the event fired from.

Again to fix just store a reference to this in a variable.

Here this refers to the element on which the listener is attached so this.id evaluates to ‘btn’.

this does not refer to the element because this is located within a function. It actually refers to the global window object.

eval

At the point where eval is called this refers to myObject. However because someFunction() is called not on some object but on the global scope, this refers to window.

Here eval is not calling a function which references this, hence this refers to myObject. Remember, at the point where eval is called this refers to myObject.

Method assigned to a variable

Here this refers to myObject as expected.

Here however printThisVar is assigned a reference to the printThis method in myObject. this will refer to window when invoking the function using printThisVar() as it is called in the global scope.

Now we copied a reference of the function to myOtherObject.printThis and we can see that this now refers to myOtherObject.

call and apply

All functions inherit from Function.prototype. Two of the methods available here are call and apply. Calling either call or apply with no parameters means that this will be bound to the window object.

firstName or lastName are not defined in the global scope so we get undefined.

If you have a function that references this, then we can use call or apply to specify what object this refers to. Calling call or apply on a function executes the function.

Here we have specified that this should refer to the person object.

call and apply do the same thing, the difference is in how we pass arguments to the function.

For call the first argument is the object to bind to this followed by a comma separated list of values which will be used as the arguments for the function.

For apply the second argument is an array of values which will be used as the arguments for the function.

bind

Another method in Function.prototype is bind which was introduced in ECMAScript 5. Note that calling bind does not execute the function. It returns a reference to a new function in which this is bound to the specified object.

Calling bind we can bind the value of this to person. Now every time we call print() the value of this will be the person object.

We can also pass parameters to bind. These will then be used as the arguments in the newly created function.

Revisiting the forEach example we had earlier in the closures section we can use bind to set the value of this. Calling .bind(myObject) would give the same result.

Arrow functions

With ES6 we can use arrow functions.

Here this is set lexically because we used the arrow function token =>. this will be set to the enclosing code’s context, which here is myObject. The same applies for the Car example.

Again in this example this refers to myObject because of the arrow function. The arrow function gets its value of this from the enclosing context. Note that arrow functions are always anonymous which is why we assigned it here to the variable innerFunction.

Leave a Reply

Your email address will not be published. Required fields are marked *