Understanding “this”

You often hear it down the hall or across the room. “JavaScript sucks, I don’t understand why I can’t reference my object”. The use of “this” in JavaScript is notorious for confusing JavaScript developers.

We are assuming here that strict mode is not turned on. If strict mode is turned on then this is undefined in global functions and in anonymous functions that are not bound to any objects.

All functions in JavaScript have properties, much like objects in languages such as Java. When a function is executed, it obtains the property this. The property this is not an assigned value until the function has been invoked. Then this will have the methods and properties of the object that invokes the function. Confused yet? Here’s an example to illustrate what I just wrote. Look at the example below and reread the paragraph, it should make sense now.

Simple Example

var duck = {
    noise : "quack",
    makeNoise : function() {
        console.log(this.noise); 
        // this will have the value of the duck object because that's what invoked the function makeNoise()
    }
};
​
duck.makeNoise(); // quack

When the property this is used in a global function, it is referring to the global window object (except in strict mode).

Global Example

var noise = "meow";
function makeNoise() {
    console.log(this.noise); 
}
makeNoise(); // meow
this.makeNoise() // meow
window.makeNoise(); // meow
duck.makeNoise(); // quack

However web applications aren’t that simple. There are use of closure, callbacks, promises, etc. How do we deal with these scenarios?

Callback

When we pass a method that uses this as a callback function, we need to bind the makeNoise method to the object animal. Otherwise it will result in undefined.

var animal = {
    noise : "quack",
    makeNoise : function () {
        console.log(this.noise); 
    }
};
$("#button-callback").click(animal.makeNoise.bind(animal)); // quack
$("#button-nonbindcallback").click(animal.makeNoise()); // undefined

Closure

Theres some confusion on the use of an inner method or a closure having access to outside data. You cannot use the variable this in the inner anonymous function forEach. It is only accessible by the function that invoked it (makeNoise). So we assign the property this to a variable that. Without the variable that, if we call “this.noise”, the result would be undefined. By assigning this to that we can reuse the noise property for the inner function.

var cats = {
    noise : "meow",
    data : [
        {name : "Zazzles", breed : "Tabby"},
        {name : "Bowie", breed : "Bengal"},
        {name : "Archer", breed : "Ocicat"}
    ],
    makeNoise : function() {
        var that = this; // standard way of naming is "that"
        this.data.forEach( function(animal) {
            console.log(animal.breed + " " + animal.name + " goes " + that.noise);
        });
    }   
};

cats.makeNoise();
// Tabby Zazzles goes meow
// Bengal Bowie goes meow
// Ocicat Archer goes meow

Using another function

Also another way of replacing the property this using the call method. Or alternatively the apply method for more than one object such as an array.

var duck = {
    noise : "quack",
    makeNoise : function() {
        console.log(this.noise); 
    }
};
var cat = {
    noise : "meow",
    qt : 3.14
}

duck.makeNoise(); // quack
duck.makeNoise.call(duck); // quack
duck.makeNoise.call(cat); // meow

Using the cats object from the closure section

var animal = {
    organizeBreeds : function() {
        var list = [];
        this.data.forEach( function(evt) {
               list.push(evt.breed);
        });
        this.breedList = list;
    }
};

animal.organizeBreeds.apply(cats, cats.data);
cats.breedList;
// ["Tabby", "Bengal", "Ocicat"]

So remember, the property this is not an assigned value until the function has been invoked. You now have the right tools (bind, call, apply, and setting this to a variable) to properly use this in every scenario.


Useful information from a Reddit user kasajian:

  1. When you call a function like method using the syntax obj.method, as in: myObject.myMethod(), then mObject is passed in as a hidden parameter named “this” and can be used from within the myMethod() function.

  2. If you call a function without using the method invocation, as in: myFunction(), then referencing “this” inside of the function does something you probably don’t want, such as access to the global variable (like window) or it doesn’t point to anything. It depends where your code is running. Don’t use “this” inside of a function that’s not invoked as a method invocation.

kasajian also references this site as a valuable source if it’s still not clear:
http://yehudakatz.com/2011/08/11/understanding-javascript-function-invocation-and-this/

 
16
Kudos
 
16
Kudos

Now read this

LRU Cache in JavaScript

This is an LRU (least recently used) cache implementation in JavaScript. It’s very efficient and uses two data structures to manage the elements. A doubly-linked list and a map gives us the following: Time complexity: O(1) Space... Continue →