Struggling for Competence

This JavaScript

In the last post I showed the basic methods of making objects in JavaScript. The trouble began however when I tried to use them. The fundamental problem I had was not understanding the rather odd behaviour of "this" in JavaScript....

Code which is just "loose" inside your script is actually being written in the context of the global object.

In the browser the global object is "window", therefore the following are equivalent:


var myVar = 3;
window.myVar = 3;

Writing all you code in global scope is not a very good idea, since any other script which gets added to the page may unintentionally interact with it.

One way to minimize the use of global variables is to create a single global variable [as] the container for your application. — Crockford p25

That sounds like a good idea, so this is what I tried:


var notes = {
    getNote: function() {
        console.log('add called');
    },
    getAllNotes: function() {
        getNote();
    }
}
notes.getAllNotes();
//=>getNote is not defined

So getAllNotes() cannot see getNote(), despite the fact that they are in the same object. The problem is that:

No binding exists between the function and the object to which it assigned. — Adams et. al. p156

That's quite different to a "normal" object orientated language, when a method knows about the other the other functions in a class and can just call them. The fix is to add "this" when calling the getNote function.


var notes = {
    getNote: function() {
        console.log('getNote called');
    },
    getAllNotes: function() {
        this.getNote();
    }
}
notes.getAllNotes();
//=> getNote called

So with that problem resolved I tried to call my getAllNotes method from an event handler. On the screen I had a "Save" button, which I wanted to invoke my code. I'm using jQuery, so I tried this:


$(document).ready(function() {
    $('#Save').click(notes.getAllNotes)
});
//=> this.getNote is not a function

So now "this" has gone wrong, it can't see the getNote function, but why?

"this" points at the object which calls the function.

The getAllNotes function has been assigned to the save buttons event handler. So when the function gets called "this" has the value of the save button. Effectively the event handler has stolen the getAllNotes function from the note object.

The fix is to wrap the call to the getAllNotes inside an anonymous function, to make sure it's the note object which calls the function, like this:


$(document).ready(function() {
    $('#Save').click(function(){
        notes.getAllNotes();
    });
});
//=> getNote called

The final thing I wanted to do was use jQuery to send some Json up to the server. The example, isn't exactly what I was doing but it illustrates the point:


var notes = {
    getNote: function() {
        console.log('getNote called');
    },
    getAllNotes: function() {
        console.log(this);
        this.getNote();
    },
    saveNotes: function() {
        $.ajax({
            url: "Note/SaveNotes",
            type: "POST",
            dataType: 'json',
            data: "",
            contentType: "application/json; charset=utf-8",
            beforeSend: function() {
                this.getAllNotes(); 
            }
        });
    }
}
$(document).ready(function() {
    $('#Save').click(function(){
        notes.saveNotes();
    });
});
//=> this.getAllNotes is not a function

So "this" has gone wrong again. The beforeSend method on $.ajax, is attempting to call this.getAllNotes(). The problem is that "this" isn't the note object, but is in fact the global object:

"this" is not captured in a closure

Normal variables are however captured, so the fix to assign "this" to a variable outside the scope of the anonymous function, like this:


var notes = {
    getNote: function() {
        console.log('getNote called');
    },
    getAllNotes: function() {
        console.log(this);
        this.getNote();
    },
    saveNotes: function() {
        var that = this;
        $.ajax({
            url: "Note/SaveNotes",
            type: "POST",
            dataType: 'json',
            data: "",
            contentType: "application/json; charset=utf-8",
            beforeSend: function() {
                that.getAllNotes();
            }
        });
    }
}
$(document).ready(function() {
    $('#Save').click(function() {
        notes.saveNotes();
    });
});
//=> getNote called

So overall I had several days worth of confusion trying to understand the behaviour of "this" in JavaScript. Not because it's wrong, but because it's so different to a statically typed language like C#. I guess ultimately the thing which foxed me was

The binding of "this" to the object happens at invocation time. —Crockford p28

Though there's quite a long way to go from reading that statement, to really understanding what it means.