JavaScript: this

Posted by bdukes on ASP.net Weblogs See other posts from ASP.net Weblogs or by bdukes
Published on Thu, 30 Jun 2011 15:00:00 GMT Indexed on 2011/07/01 0:22 UTC
Read the original article Hit count: 823

JavaScript is a language steeped in juxtaposition.  It was made to “look like Java,” yet is dynamic and classless.  From this origin, we get the new operator and the this keyword.  You are probably used to this referring to the current instance of a class, so what could it mean in a language without classes?

In JavaScript, this refers to the object off of which a function is referenced when it is invoked (unless it is invoked via call or apply). What this means is that this is not bound to your function, and can change depending on how your function is invoked. It also means that this changes when declaring a function inside another function (i.e. each function has its own this), such as when writing a callback. Let's see some of this in action:

var obj = {
    count: 0,
    increment: function () {
        this.count += 1;
    },
    logAfterTimeout = function () {
        setTimeout(function () {
            console.log(this.count);
        }, 1);
    }
};
obj.increment();
console.log(obj.count); // 1
var increment = obj.increment;
window.count = 'global count value: ';
increment();
console.log(obj.count); // 1
console.log(window.count); // global count value: 1
var newObj = {count:50};
increment.call(newObj);
console.log(newObj.count); // 51
obj.logAfterTimeout();// global count value: 1
obj.logAfterTimeout = function () {
    var proxiedFunction = $.proxy(function () {
            console.log(this.count);
        }, this);
    setTimeout(proxiedFunction, 1);
};
obj.logAfterTimeout(); // 1
obj.logAfterTimeout = function () {
    var that = this;
    setTimeout(function () {
        console.log(that.count);
    }, 1);
};
obj.logAfterTimeout(); // 1

The last couple of examples here demonstrate some methods for making sure you get the values you expect.  The first time logAfterTimeout is redefined, we use jQuery.proxy to create a new function which has its this permanently set to the passed in value (in this case, the current this).  The second time logAfterTimeout is redefined, we save the value of this in a variable (named that in this case, also often named self) and use the new variable in place of this.

Now, all of this is to clarify what’s going on when you use this.  However, it’s pretty easy to avoid using this altogether in your code (especially in the way I’ve demonstrated above).  Instead of using this.count all over the place, it would have been much easier if I’d made count a variable instead of a property, and then I wouldn’t have to use this to refer to it. 

var obj = (function () {
    var count = 0;
    
    return {
        increment: function () {
            count += 1;
        },
        logAfterTimeout = function () {
            setTimeout(function () {
                console.log(count);
            }, 1);
        },
        getCount: function () { return count; }
    };
}());

If you’re writing your code in this way, the main place you’ll run into issues with this is when handling DOM events (where this is the element on which the event occurred).  In that case, just be careful when using a callback within that event handler, that you’re not expecting this to still refer to the element (and use proxy or that/self if you need to refer to it).

Finally, as demonstrated in the example, you can use call or apply on a function to set its this value.  This isn’t often needed, but you may also want to know that you can use apply to pass in an array of arguments to a function (e.g. console.log.apply(console, [1, 2, 3, 4])).

© ASP.net Weblogs or respective owner

Related posts about General Software Developm

Related posts about JavaScript