JavaScript ‘this’ Gotchas

    Craig Buckler
    Share

    In my previous post, we looked at JavaScript’s this statement and how it can change depending on the context of the function call. Today, we’ll examine several situations where this could catch you out…

    1. Forgetting ‘new’

    Consider the following code:

    
    window.WhoAmI = "I'm the window object";
    
    function Test() {
      this.WhoAmI = "I'm the Test object";
    }
    
    var t = Test();
    alert(window.WhoAmI); // I'm the Test object
    alert(t.WhoAmI); // t is undefined
    

    What we really meant is:

    
    var t = new Test();
    

    The omission of the new statement gave us undesirable results. Other languages would throw an error when faced with a direct call to a constructor but JavaScript simply treats it like any other function call. this is taken to be the global window object and no value is returned from Test() so t becomes undefined.

    This situation can be fixed if you’re writing a JavaScript library for third-party developers. Refer to Fixing Object Instances in JavaScript.

    2. Module madness

    This one will give you a headache. Examine the following code which uses a module pattern:

    
    window.WhoAmI = "I'm the window object";
    
    var Module = function() {
    
      this.WhoAmI = "I'm the Module object";
    
      function Test() {
        this.WhoAmI = "I'm still the Module object";
      }
    
      return {
        WhoAmI: WhoAmI,
        Test: Test
      };
    
    }();
    
    alert(Module.WhoAmI); // I'm the Module object
    alert(window.WhoAmI); // I'm the Module object
    Module.Test();
    alert(Module.WhoAmI); // I'm still the Module object
    

    The code looks logical — so why is window.WhoAmI saying it’s the module object?

    We need to remember that we have a self-executing function. It’s results are returned to the Module variable but, when it’s first run, Module doesn’t exist. this is therefore the global window object. In other words, this.WhoAmI = window.WhoAmI = "I'm the Module object".

    The function returns a JavaScript object with a WhoAmI property with a value of 'WhoAmI'. But what does that refer to? In this case, the JavaScript interpreter works up its prototype chain until it magically finds window.WhoAmI ("I'm the Module object").

    Finally, we run the Test() method. However, Module has now been created so, within the Test function, this refers to the Module object so it can correctly set the WhoAmI property.

    In summary, avoid using this within a module to refer to the module itself! You should never need it.

    3. Method misconceptions

    Here’s another JavaScript pattern which will screw with your synapses:

    
    var myObject = {};
    
    myObject.method = function() {
    
      this.WhoAmI = "I'm myObject.method";
    
      function Test() {
        this.WhoAmI = "I'm myObject.method.Test()";
      }
    
      Test();
    
      return this.WhoAmI;
    };
    
    alert(myObject.method()); // I'm myObject.method
    

    In this example, Test() is a private function executed within myObject.method(). At first glance, you would expect this within Test() to reference myObject. It doesn’t: it refers to the global window object since it’s just another function.

    If you want to reference myObject within the private function, you’ll require a closure, for example:

    
    var myObject = {};
    
    myObject.method = function() {
    
      this.WhoAmI = "I'm myObject.method";
      var T = this;
    
      function Test() {
        T.WhoAmI = "I'm myObject.method.Test()";
      }
    
      Test();
    
      return this.WhoAmI;
    };
    
    alert(myObject.method()); // I'm myObject.method.Test()
    

    4. Referencing methods

    Here’s a little code which, fortunately, will work exactly as you expect:

    
    var myObject = {};
    
    myObject.WhoAmI = "I'm myObject";
    
    myObject.method = function() {
      this.WhoAmI = "I'm myObject.method";
    };
    
    // examine properties
    alert(myObject.WhoAmI); // I'm myObject
    myObject.method();
    alert(myObject.WhoAmI); // I'm myObject.method
    

    Let’s make a minor change and assign myObject.method to another variable:

    
    // examine properties
    alert(myObject.WhoAmI); // I'm myObject
    var test = myObject.method;
    test();
    alert(myObject.WhoAmI); // I'm myObject
    

    Why hasn’t myObject.WhoAmI changed? In this case, the call to test() acts like a regular function call so this refers to the window object rather than myObject.

    If you think that’s nasty, wait until we take a look at JavaScript event handlers in my next post!

    note: Want more?

    If you want to read more from Craig, subscribe to our weekly tech geek newsletter, Tech Times.