Working with the JavaScript “this” Keyword

JavaScript's "this" keyword can be a bit tricky to work with depending on the context in which it's used. When it's used with patterns such as the Prototype or Revealing Prototype patterns working with "this" can be challenging in some cases. Unlike languages such as C# or Java, "this" can change context. For example, if a Calculator object named calc calls an add() function then "this" represents the Calculator object which means you can easily access any variables defined in the object such as a variable named tax by simply using this.tax.


calc.add(2, 2); //Using "this" inside of the add() function gets you to the calc object

 

However, if add() makes a call to another function then "this" changes context and no longer represents the Calculator object. In fact, "this" will change to the window object which means you can no longer access variables defined in the Calculator object such as tax. That presents a bit of a problem that’s especially challenging if you’ve never dealt with it before.

There are several ways to handle this challenge. First, you can pass "this" as a parameter to other functions. An example of passing "this" between functions is shown next. If a Calculator object calls a clearNumbers() function then you can easily access the Calculator object's constructor variables within the function. However, once clearNumbers() calls other functions such as setVal() or setEquation(), "this" changes context. To account for the change, the code passes "this" as a parameter to each of the functions and they then use it like normal. Although this type of code works, it pollutes your function parameters in some cases and becomes a little messy to work with (at least in my opinion).

 

var Calculator = function (eq) {
    //state goes here
    this.eqCtl = document.getElementById(eq);
    this.lastNumber;
    this.equalsPressed;
    this.operatorSet;
this.tax; }; Calculator.prototype = function () { //private members var add = function (x, y) { this.eqCtl.innerHTML = x + y + this.tax; }, subtract = function (x, y) { this.eqCtl.innerHTML = x – y + this.tax; }, setVal = function (val, thisObj) { thisObj.currNumberCtl.innerHTML = val; }, setEquation = function (val, thisObj) { thisObj.eqCtl.innerHTML = val; }, //Other functions omitted for brevity
clearNumbers = function () { this.lastNumber = null; this.equalsPressed = this.operatorSet = false;

//Pass the Calculator object that called clearNumbers()
//to other functions as a parameter
setVal('0', this); setEquation('', this); }; //public members return { add: add, subtract: subtract, clearNumbers: clearNumbers }; } ();


Another technique that can be used involves JavaScript's call() function. This function can be used to invoke functions and set the context of "this" while the call is being made. For example, if you want to call a function named setVal() and preserve the current value of "this" as the call is made then you can do the following:

 

setVal.call(this, 'yourParameterValue');


The current value of "this" will be passed along automatically to the setVal() function and it can safely use this.tax in the case of a Calculator object.

The following code uses the call() function to update the code shown earlier. The clearNumbers() function uses JavaScript's call() function to invoke the setVal() and setEquation() functions and preserve the current value of "this" in the process. Notice that the setVal() and setEquation() functions no longer need the extra parameter as the functions shown earlier did and can simply use "this" to access Calculator object variables defined in the object's constructor. This simplifies the call by eliminating the need for the extra parameter and makes the code a lot cleaner.

 

var Calculator = function (eq) {
    //state goes here
    this.eqCtl = document.getElementById(eq);
    this.lastNumber;
    this.equalsPressed;
    this.operatorSet;
this.tax; }; Calculator.prototype = function () { //private members var add = function (x, y) { this.eqCtl.innerHTML = x + y + this.tax; }, subtract = function (x, y) { this.eqCtl.innerHTML = x – y + this.tax; }, setVal = function (val) { this.currNumberCtl.innerHTML = val; }, setEquation = function (val) { this.eqCtl.innerHTML = val; }, //Other functions omitted for brevity clearNumbers = function () { this.lastNumber = null; this.equalsPressed = this.operatorSet = false;



//Set context of "this" to the Calculator object that called clearNumbers()
setVal.call(this, '0'); setEquation.call(this, ''); }; //public members return { add: add, subtract: subtract, clearNumbers: clearNumbers }; } ();


Another example of where “this” gets tricky is inside of jQuery event handlers. For example, assume that an init() function is called that adds a click event to DOM elements. What if you want to get to a value of “this” representing the container Calculator object while inside of the click event handler function? The context of “this” changes to the anchor tag making it challenging. Two potential options that can be used are shown next.

The first option is to store the value of “this” as a variable outside of the click event handler function. By doing this a closure is created and you can still access the original value of “this” when the event fires:

 

Calculator.prototype = {
    //private members
    init: function() {
        //Option 1 for working with "this"
        var calcObject = this;
        $('a').click(function () {
            //Can't simply use this or $(this) 
            //since "this" represents the anchor now
            //calcObject will represent the Calculator object
            calcObject.highlight($(this));
        });
    },

    highlight: function(anchor) {
        anchor.toggleClass('highlight');
    }
};


Another option is to use an overloaded version of various jQuery event handlers such as on() to pass “this” and make it accessible through the event object:

 

Calculator.prototype = {
    //private members
    init: function() {
        //Option 2 for working with "this"
        //Pass "this" into the on() call
        $('a').on('click', { calcObject: this }, function (event) {
            //Access the original value of "this" 
            //through the event object's data property
            event.data.calcObject.highlight($(this));
        });
    },

    highlight: function(anchor) {
        anchor.toggleClass('highlight');
    }
};


Notice that “this” is assigned to an object literal property named calcObject in the on() parameters. Once the click event fires the event object passed to the callback function can be used to get to the data property which exposes the calcObject value that was passed in.

Although working with JavaScript’s “this” keyword can be challenging in some scenarios, there are several different techniques that can be used to make it easier to work with. Have any other techniques you like to use? Feel free to leave a comment and share your technique with everyone.

 

 

 

Videos on JavaScript and jQuery


If you're interested in additional information about structuring JavaScript code check out my Structuring JavaScript Code course created for PluralSight. Here's a sample from the course covering closures.

Demo - Working with Closures in JavaScript

 

A sample video from the jQuery programming course that covers using the each() function is shown next:


Demo – Using jQuery’s each() Function



comments powered by Disqus

10 Comments

  • Hey Dan, I may be wrong on this (pun intended, ha!), but for your first scenario of methods calling other class methods, could you not just do this:

    this.setVal('0');
    this.setEquation('');

    This should retain the value of 'this' inside of those functions. This (ha!) is the way I've always called other methods inside of a JavaScript object.

  • Michael,

    You'd think that would work (I know I did initially :-)) but "this" will actually change context and represent the window object inside of setVal() and setEquation() when using the Revealing Prototype Pattern. Weird....I know, but that's one of those tricky things JavaScript does. Plus, you can't use this.functionName() in that scenario to call a "private" function since the function actually won't be found and you'll see a JavaScript error. Tricky stuff for sure.

    Dan

  • Ah, I missed your use of the revealing prototype pattern. I typically just declare my functions on the prototype object and it isn't an issue. Thanks for the tips!

  • First off I think this is a great subject for Javascript newbies, since even more advanced users sometimes get bewildered by the change in "this". I would like to emphasize that "this" inside a function is the parent object of the function, which for functions that are not direct members of Javascript objects is the "global" object. "window" is just the global object in a browser environment, but not in a unit test framework, a command line console or NodeJS. This also allows a trick: var global=(function() { return this; })(); that will return the global object anywhere and for any flavour of Javascript.

  • I’ve learned a lot from your blog here! Keep on going, my friend, I will keep an eye on it.

  • Dan, I saw pretty often a technique, when the first local variable assignment inside container function is

    var self = this;

    It preserves the function context, and is available as a closure in all inner sub-functions, for your example:

    self.setVal('0');

    Doesn't this work for prototype?

  • Hi Dan,

    Great 2 part article and I downloaded the App AccountsAtAGlance. I ran into couple of problems

    1) Video does not play on Firefox 9.* Works ok on IE 9

    2) The accounts position only shows: ${pos.security.symbol} S{pos.Shares}.... seems like these are not computed

    3) Account details $ACCOUNTTITLE{} - {{tmpl '#AccountDetailsTemplate_Base'}}

    What may I be missing? The database seems to be created OK..

  • Hi Nealbob,

    Here are some general things to look into:

    1. I'm guessing this is a MIME Issue. Firefox is probably requiring that a MIME type be served up to show video properly. If you switch to IIS Express (instead of the Visual Studio server) then you can define the appropriate MIME type for an MP4 in web.config. Basically it's a server config issue.
    2/3: This is normally caused by an error on the server-side due to a DB or other problem. It could be the database connection string needs updated to your server name (check web.config) or a variety of other issues. I'd download and run Fiddler (http://www.fiddler2.com) to check traffic and see if any errors are occurring behind the scenes. Or, set breakpoints in the code on the server and track any config issues down from there.

    Dan

  • Hi Dan

    Thanks; I figured there was some DB connection issue for issues 2/3. For item 1, since I am running on windows 7/64 is it just possible to install IIS express and use it? I am not experienced with IIS express and how to deploy your app to use IIS express. That is question #1, and then I'd really appreciate if you can elaborate/give an example of the MIME type config for MP4 in web.config.

    Thanks for responding, Dan.

    Neal

  • This is great resource for coders. And true whilst "this" keyword for JavaScript is to be used extensively, it can be tricky to figure it. But you have detailed it out quite nicely. Had a marvelous insight into "this" coding

Comments have been disabled for this content.