Understanding the JavaScript “this” keyword: Part 1

This article is the first of two articles which explain the this keyword in JavaScript. In this first post, we’ll look at what the value of this will be under various invocation scenarios. In the second article, we’ll look at how these rules can be bent by the caller.

Before we begin, I’d like to go over two JavaScript concepts. It’s crucial these are understood to be able to grasp the behaviour of this:

  1. The value of this within a function is not resolved until the function is called.This means that one function can be called 10 different times, and each time a different value of this could be observed.
  2. Whenever you name a function in JavaScript, what you actually do is create a named variable which references that function (i.e. the named variable points to the function). When you assign that named variable to another variable (i.e. alias the function), what you actually do is pass that reference by value, which leaves both variables pointing to the same function.
    // "foo" points to a function which alerts "hi"
    function foo() {
        alert("Hi");  
    }
    
    // Set "b" to point to the same function as "foo" points to (which alerts "hi").
    var b = foo;
    
    // "bar" points to a function which accepts a parameter which points to a function.
    // The body of the function simply executes the function provided.
    function bar(f) {
        f();   
    }
    
    // Pass the function pointed to be "foo" to the function pointed to by "bar".
    bar(foo);

    This means you can have one function, which can be pointed to by multiple variables. If this is still unclear, perhaps the answers to this Stack Overflow question will help the point sink in.

Once you’ve understood the two concepts above, the rules as to what the value of this is is quite straightforward; it’s the rule-bending we discuss in the next article that makes everything more more complicated!

  1. If you access the function via a property of an object, the value of this will be the object.
    var obj = {
        foo: function () {
            alert(this.bar); 
        },    
        bar: 4
    };
    
    obj.foo(); // alerts "4", as `this` inside `foo()` is `obj`.
    
  2. If the variable you access the function from is just a normal variable, the value of this depends on whether you’re in strict mode. Unless you know otherwise, chances are you won’t be.
    • If you are in strict mode, this will be undefined
    • If you aren’t in strict mode, this will the global object. In browsers, the global object is window.
    function foo() {
        "use strict";
        
        alert(typeof this === "undefined");
    }
    
    function bar() {
        alert(typeof this === "object" && this === window);
    }
    
    foo();  // alerts `true`, as inside strict mode, `this` is undefined
    bar();  // alerts `true`, as inside non-strict mode, this is the global (window) object
    

That’s all there is to it! One common “got-cha” however is when you pass a function (which was pointed to by a object member) as a parameter to another function, people still expect this to be the object.

// Define an object which has a property "foo", which points to a function.
// that function alerts "this.val".
var obj = {
    foo: function () {
        alert(this.val);   
    },

    val: "bar"
};

// Remember, if the function we're calling is a member of an object, the value of `this` will be the object.
// In this case "this" resolves to "obj", so we see "bar" being alerted.
obj.foo();

// Lets define another function, which accepts a function as a parameter. All it does is call that function.
function baz(f) {
    f(); 
}

// Now we pass the function pointed to by "obj.foo" to "baz()". "this" will now be the global object, and
// "this.val" will be undefined.
baz(obj.foo);

No! Don’t forget when you alias a function (either by assigning it to another variable or passing it as a parameter to another function), a new pointer to the same function is created. That new pointer has it’s own behaviour; and it’ll follow behaviour #2.

With the rules out of the way, lets go through some examples to see the rules being applied in practise;

function foo() {
    console.log(this);   
}

foo(); // This will be the global object ("window")

var obj = {
    bar: foo  
};

obj.bar(); // This will be "obj"

var baz = obj.bar;

baz(); // This will be the global object ("window") again.

Leave a Reply

Your email address will not be published. Required fields are marked *