JavaScript’s “this” Foils an OO Guy

There are a lot of good posts on this topic, but I wasn’t paying attention apparently – so JavaScript folks can stop reading now unless you want to mock me.

Most of my real development has been in object oriented languages, C++, Objective-C and Java primarily, so when I decided to tidy up some JavaScript I’d written I tried to OO it up a bit.  Not the wisest path, but it’s my comfort zone…

Anyway here’s what tripped me up.  The following is a contrived example for discussions sake:

function Enabler () {
    // Instance variables
    this.username = $('#username');
    this.loginButon = $('#loginButton');

    // Event handlers
    this.enableLogin = function () {
        $(this.loginButton).prop('disabled',
            $(this.username).val().length <= 8 );
    }

    // Binding
    $(this.username).bind('keyup', this.enableLogin);
}

$(document).ready(function () {
    var enabler = new Enabler();
}

Looked good to me. But the enableLogin function caused an “Uncaught TypeError: Cannot read property ‘length’ of undefined” the first character I typed. The JavaScript folks are probably laughing at this point. Poking around I determined that this was not my instance of Login but input#username!

But of course…. because this in JavaScript is the owner of the function being called, and functions can change ownership. Above I bound the function to the text field which changed it’s owner. That’s a gross simplification, for the whole story you can read a post like Understanding JavaScript’s This With Clarity and Master It and also learn about Arrow Functions. Either way, there are a couple simple fixes to just insure the correct owner. One is with bind as follows:

// Event handlers
this.enableLogin = function () {
    $(this.loginButton).prop('disabled',
       $(this.username).val().length <= 8 );
}
// Binding
$(this.username).bind('keyup',
                    this.enableLogin.bind(this));

Another, that works with ECMAScript 6 browsers (not IE or Safari) is by using an Arrow Function which uses a lexical bind of this:

// Event handlers
this.enableLogin = () => {
    $(this.loginButton).prop('disabled',
       $(this.username).val().length <= 8 );
}
// Binding
$(this.username).bind('keyup', this.enableLogin);

But the real solution is, I shouldn’t try and force my JavaScript square peg into an OO round hole.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s