JavaScript for the C# Developer Part 8 – WTF is this?

Previous: JavaScript for the C# Developer Part 7 – Prototypal Inheritance

In JavaScript for the C# Developer Part 6 – Objects I promised to cover JavaScript’s very confusing treatment of the this keyword.

 

 

The this keyword

Many languages use the this keyword or something similar, e.g. Me in Visual Basic, to represent the current object instance. JavaScript does too (http://jsfiddle.net/DougWare/rX8JA/).

The preceding example shows that within an object this works exactly like you would expect based on experience with C#. In the object x, this is equal to x. In the object y, this is equal to y.

If only it were that simple

The way this works in the example is obvious, because whatsThis is defined inside both objects. It makes sense that this refers to the object. Unfortunately it is not always so obvious because of the flexibility JavaScript allows with functions. Consider this example (http://jsfiddle.net/kgJ87/).

This example shows three different object instances as the value of this within the function globalWhatsThis: x, y, and window. This is actually a byproduct of the syntax – from a runtime perspective; this example is essentially the same as the first example. The declaration of the whatsThis members in the two object literals assign the value of the globalWhatsThis variable (which is a function) to whatsThis. Even though the function is declared outside the objects, the runtime effect is that each object has its own copy of the function.

A very simple change to the object literals to invoke globalWhatsThis from the whatsThis member functions has a profound effect on the results (http://jsfiddle.net/DougWare/cZ6p7/).

DOM element events

It should be clear that using this inside a function that is not part of an object is dangerous because the functionality of the called function depends on the caller’s implementation. This problem is often encountered with DOM element events. Consider this example where a button’s onclick handler contains JavaScript to call a global function (attached to window) (http://jsfiddle.net/DougWare/w46yC/).

Contrast that example with one where the function is attached directly to the event (http://jsfiddle.net/DougWare/kdTDN/).

If you use the jQuery framework (or something similar) to manage events you won’t encounter this because the framework ensures this will be the element that raised the event. Either way, you should understand that this is the same syntactical illusion as before; the value of whatsThis (a function) is assigned to the element object’s onclick property and is therefore part of the button element object! If the function calls a function that is part of the window, this will be window (http://jsfiddle.net/DougWare/kSEwE/).

Bind

There are a number of ways you can control the value of this instead of just writing code that uses it and hoping for the best! Among these is the bind() method of the function object. Bind is available in most modern browsers, but it isn’t available in versions of IE before 9.0. However, you can add it if you need it or use a framework like prototype that includes it.

The bind() method takes an object as an argument and returns a new function bound to the object of your choice to use as this (http://jsfiddle.net/DougWare/e7fBy/).

Callbacks

The most common error I see with regards to this is its improper use in scenarios where the developer is attempting to share data between the function that sets up the callback and the callback function. The SharePoint CSOM documentation contains numerous examples of this type of error. Here is an example from http://msdn.microsoft.com/en-us/library/jj163201(v=office.15).aspx.

Every instance of this in the sample code refers to window and these are therefore global variables just waiting to cause issues when there are multiple instances of the callback waiting!

An easier to identify variation of this mistake is found in callbacks bound to event handlers. In this scenario, this is the DOM element but this is the window in the callback for reasons that you should now understand. Here is an example that demonstrates the issue with a couple of buttons that setup callbacks via the built-in setTimeout() function (http://jsfiddle.net/DougWare/vfR42/).

When you run this example and click the buttons, undefined displays twice after a short delay because this.someData is undefined – this refers to window.

Using bind() with callbacks

The previous example can be fixed to bind the button elements to the appropriate callback (http://jsfiddle.net/DougWare/KByPj/).

Keep in mind that bind takes any object as its argument. In the example I bound this (the button) but I could use any object I want to act as this in the callback.

–Doug

Author: Doug Ware