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 Enabler 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 its owner to that. 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 using 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 at time of publish) 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.