javascriptwindowthis

"This" becomes "window" JavaScript


I'm trying to develop a small game and I have the following problem: I have a pseudo class "Cannon", each Cannon has an array that stores the areas it should guard and an array that stores "intruders" that have entered one of those guarded areas. I created the next function as part of Cannon's prototype:

Cannon.prototype.checkIntruderLeftGuardedAreas = function(){
    debugger;
    this.intruders = this.intruders.filter(function(intruder){
        for(var i = 0, l = this.guardedAreas.length; i < l; i ++)
        {
            if(intruder.inInsideGuardedArea(this.guardedAreas[i]))
            {
                return true;
            }
        }
        return false;
    });
}

On the third line I'm trying to filter those intruders that have left the guarded areas, but "this" references to "window" instead of the Cannon objetc that invoked the function.

I also tried this code:

var intrudersArray = [];
    for(var i = 0, l = this.guardedAreas.length; i < l; i ++)
        {
            for(var j = 0, k = this.intruders.length; j < k; j++)
            {
               if(this.intruders[j].inInsideGuardedArea(this.guardedAreas[i]))
               {
                   intrudersArray.push(this.intruders[j]);
               }
            }

        }

        this.intruders = intrudersArray;

This, according to my logic, does the same thing than the previous block of code: filter the array of intruders. The problem is that on the 6th line where the "if" begins, suddenly "this" references to "window"!. Before reaching that if condition, "this" references to the Cannon object that called the function.


Solution

  • Yep, scoping can get tricky, you could try the following:

    Cannon.prototype.checkIntruderLeftGuardedAreas = function(){
        var self = this;
    
        self.intruders = self.intruders.filter(function(intruder){
            for(var i = 0, l = self.guardedAreas.length; i < l; i ++)
            {
                if(intruder.inInsideGuardedArea(self.guardedAreas[i]))
                {
                    return true;
                }
            }
            return false;
        });
    }
    

    Notice the line var self = this;. It's purpose is saving a reference to your cannon instance to use inside nested callbacks (note how this is now self inside filter) in order to avoid scope issues, it's common to see such stuff in jQuery code.

    This practice ensures you reference your cannon without the need to track what's going on with this, self like that is obvious at first glance.