Using Prototype (and ensuing difficulties)

Now that classes are over and my website is (mostly) done, I have the time to go back and review the code I wrote for the shared workspace. It was well-commented, but the code itself could use some legibility improvements. Plus, there are some interesting patterns I would like to try and apply, the simplest of which is the Constructor Pattern.

While writing the code, I was wondering about the performance cost incurred when many instances of the same type define the same functions. I never found a great answer to this, until just recently.

In the freely-available Essential JavaScript Design Patterns 1.1, author Addy Osmani describes the optimal solution using the "prototype" keyword.

I expect this is a pretty obvious technique to any experienced JS developer, but I'm still learning! Probably just another example of JavaScript's object implementation throwing a rookie for a loop, I guess.

Unfortunately, this isn’t a simple search-and-replace operation. The most notable difficulty comes when dynamically creating draw functions. Click here to see my original “createDrawFunction()” function.

Notice how each anonymous function pushed to the “functioncalls” list uses members of the currently-active drawing (i.e. “movePen()”, “xpos”, “ypos” etc.). When this code appears in a prototype function, those members are not in scope.

“Just use the ‘this’ keyword, Mike!” some might say. (Actually, I said that at first.) Unfortunately, the meaning of “this” changes in the context that these anonymous functions are actually called, so that doesn’t solve the problem. What we need is to bind the context of the function when we create it.

JavaScript’s “apply()” method lets you change the context of a function, but it immediately calls that function. Not exactly what we want, but we can use it to write our own “bind()” method. We can even extend all JavaScript functions to supporting binding! Here’s how:

if (typeof Function.bind !== 'function') {
    Function.prototype.bind = function(scope) {
        var _function = this;
        return function() {
            return _function.apply(scope, arguments);
        }
    };
}

With this function, we can safely encapsulate the context each time we create a new drawing function. Perfect! Click here to see how I re-wrote “createDrawFunction()” to work using function Prototypes.

Comments

Sorry! Comments aren't supported yet.