Understanding the JavaScript “this” keyword: Part 2

In the previous article, we uncovered the fundamental rules around how the value of this is determined when inside a function. If you haven’t read it yet, head over to the first article, and pop back here when you’re done.

From this point onwards, we’re going to explore a number of JavaScript features that throw those rules out of the window, and allow the caller to choose the value of this.

  1. Changing the value of this using call() and apply()We know if you call someObject.foo() that this inside foo will be someObject. What if we want it to be anotherObject?

    Well, we could do this;

    anotherObject.foo = someObject.foo;
    anotherObject.foo();
    delete anotherObject.foo;

    Bit of a hack, no? Enter call() and apply(). All you have to do is;

    someObject.foo.call(anotherObject);

    What if you want to pass arguments to foo() as well? No problem!

    someObject.foo.call(anotherObject, 1, 2, "abc");

    apply() works exactly the same, but the difference is how they let you pass arguments to the function. call() expects each argument as a separate parameter, whereas apply() expects a single array, whose elements are all the parameters. The equivalent apply() call for the above would be;

    someObject.foo.apply(anotherObject, [1, 2, "abc"]);
  2. Forcing the value of this using bind()bind() is a tricky addition to the JavaScript language (introduced in ES5). If you call someObject.foo.bind(anotherObject), bind() will return a new function; and no matter how you call the returned function (even using call() and apply()), the value of this will always be anotherObject.
    var obj = {
        val: 4
    };
    
    function foo() {
        alert(this.val);
    }
    
    var bar = foo.bind(obj);
    
    foo(); // behaves as expected; alerts `undefined` as `foo` is not attached to an object
    bar(); // breaks the rules! alerts `4` because `bind()` sets `this` to `obj`.
    
    bar.call(window); // this has no effect; still alerts `4`.

    Try it yourself!

    You might wonder how bind() works; but even if ES5 hadn’t included bind(); well, we could roll out our own really easily;

    Function.prototype.ourBind = function(thisArg) {
        var that = this;
    
        return function() {
            return that.apply(thisArg, arguments);
        };
    };

    We could then use ourBind() exactly how we’d use bind(); see it in action on jsFiddle!

  3. The new keyword has the last say…One last feature in JavaScript that I’d like to mention before finishing this article is the new keyword.

    If you’re not quite clued up on the behaviour of new you can read more about it here.

    Using new when calling a function is the final way to change the value of this when calling a function. When you use new, this points to a new object, whose “prototype” is set to the prototype of the function you called new on. Yep; that might take a few reads to sink in.

    The only use case for this is when creating instances of a object; but I just wanted to complete the list of “ways-this-can-be-changed”.

That concludes the articles on this; I hope you now have a much better understanding about how it works! If you want to read a few more articles to help it sink in, I’d recommend this quirksmode article and this Stack Overflow question

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.

Tracking/ joining parallel AJAX requests with jQuery

When launching a number of AJAX requests simultaneously, it can often be painful to track the requests, and seemingly necessitates the introduction of counter variables to detect when all the AJAX requests have completed. However, since jQuery 1.5, the various AJAX methods have returned a Promise object (an object which exposes only the “safe” methods of a Deferred). This, coupled with the jQuery.when method, allows you to easily add handlers to handle either the successful completion of all AJAX requests, or the failure of one; without the need for you to track anything yourself! To use this approach, simply pass the Promise’s returned by your AJAX calls as arguments to jQuery.when(), then add handlers using the done(), fail() and always() to the Promise returned by jQuery.when(), as demonstrated in the example below.

jQuery.when(jQuery.get('/foo'), jQuery.post('/bar'), jQuery.get('/baz')).done(function (a, b, c) {
    $('#output_a').text(a[0]);
    $('#output_b').text(b[0]);
    $('#output_c').text(c[0]);
});

The ith argument passed to done() is an array of arguments that correspond to the response of the ith Promise passed to when() (i.e. the arguments are available in the order they were provided; the order the responses were received in make no difference). For the example above, this means that a, b and c are all arrays of [ data, textStatus, jqXhr ]. To get the textStatus of the second AJAX call we’d use b[1]. To get the jqXhr object of the 3rd AJAX call we’d use c[2]. All fail() handlers are invoked the first time one of the provided Promises fails. Here however, the arguments are provided as they would be passed into a fail() handler bound directly to the failed AJAX request; i.e. the first argument is the jqXHR object, the second is the textStatus and the third is the error thrown. The behaviour of always() changes depending on whether a request failed or not; if all requests succeed, always() behaves like done(). If a request fails, always() behaves like fail().

jQuery.when(jQuery.get('/foo'), jQuery.post('/bar'), jQuery.get('/baz')).done(function (a, b, c) {
    $('#output_a').text(a[0]);
    $('#output_b').text(b[0]);
    $('#output_c').text(c[0]);
}).fail(function (jqXhr, textStatus, error) {
    alert('A request failed with the error "' + jqXhr.status + '"');
}).always(function () {
    // because of the varying parameter behaviour, its difficult to
    // do anything which uses them.

    $('#loading_spinner ').hide();
});

The signature of jQuery.when() (e.g. having to pass each Promise as a separate argument) can be cumbersome, and make it seem impossible to use when the number of AJAX requests you have cannot be determined. However, we can easily use Function.apply(), and use jQuery.when() using an array of Promise‘s instead;

var ajaxRequests = [jQuery.get('/foo'), jQuery.post('/bar'), jQuery.get('/baz')];

jQuery.when.apply(jQuery, ajaxRequests).done(function () {
    for (var i=0;i<arguments.length;i++) {
        console.log('Response for request #' + (i + 1) + ' is ' + arguments[i][0]);
    }
});

If you have not come across the arguments object yet, you can read about it here. As can be seen in the example above, apply() returns the “master-Deferred” the same way using jQuery.when() directly does, allowing you to bind done(), fail() and always() handlers as before.


For more reading, check out the jQuery documentation for jQuery.when(), or the question on Stack Overflow that triggered me to write this blog post!

Why should(n’t) you rely on CDN’s for hosting libraries?

CDNs such as Google’s allow developers to link to resources on it at no cost. This article addresses the benefits, and explains any drawbacks of taking advantage of this seemingly generous offer!

So what are the advantages?

  1. The speed of the download should be quicker. CDN’s work by installing endpoints in locations closer to the user, both geographically and topologically. It’s also likely the CDN offered by the likes of Google is also more optimized and beefy than anything a developer would be able to provide themselves. All of these factors should result in lower latency and a faster download speed.
  2. The chances of a cache-hit are increased. For a file to be possibly cached, the user must have accessed it before. If multiple websites link to the same resource (like multiple websites use the resources on Google’s CDN), the chances of the user accessing the file is increased compared to you hosting the file yourself (and so only your website using the resource).
  3. It allows parallel downloads. Browsers are restricted by how many requests they can make concurrently to a domain/ IP address. The limit is browser version specific. By hosting resources on different domains/ IP addresses, you increase the amount of resources you can concurrently download.
  4. It frees up your servers resources. Hitting a CDN rather than your server means it has to deal with one less request. That’s less bandwidth, less connections and less load and less money spent!

Sounds good so far! Are there any disadvantages?

  1. Hosting files on an additional domain requires an additional DNS lookup to resolve it. This requires a request to a DNS server. It’s worth noting that DNS entries are cached, so this DNS lookup won’t hit you every time. Whether this additional delay is worth the speed increase of the quicker download remains to be seen.
  2. CDNs do go down. Two outages spring to mind that had a major affect on websites relying on that CDN. The MathJax CDN went down a few weeks ago, and the Google CDN was unavailable for some users a few months ago. If your website relies on the resources on that CDN, your website goes down with the CDN.

Anything I can do about those disadvantages?

It just so happens you can do something about the second disadvantage. It’s possible (and easy!) to detect whether the CDN you’re using is unavailable, and if it is, revert to your own copy of the resource. There’s no speed penalty using this approach if the CDN is working fine.

To do this, place an additional <script> tag after the <script> tag referencing the CDN. Inside that, check whether the resource was loaded (in the example below, we check that jQuery is available). If it was, the resource was loaded and you don’t need to do anything. If it wasn’t, simply load your own copy of the resource;

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script>
    if (typeof window.jQuery === "undefined") {
        document.write("<script src="/assets/js/jquery-1.7.1.min.js"></scr" + "ipt>");
    }
</script>

For further reading, there are a number of Stack Overflow questions which address these points.