Liz Douglass

Archive for January 2009

Encountering JavaScript

leave a comment »

As of April last year I’d never done any web development at all. Nada. No HTML even. I’ve learnt a lot in the last few months and have been very impressed by the languages and tools that I have used since then. One language that I had heard of but not ever encountered until recently is JavaScript. Until a couple of weeks ago, I knew only two things about it: 1) don’t be fooled into thinking it’s Java, 2) people seem to find it tricky to use.

A few weeks ago I was working on a story that used Thickbox, which is written in JavaScript, and found a sticking point that we only really understood from reading the code (a story for another day perhaps). My colleague, Adam, kindly lent me his copy of JavaScript: The Good Parts and I have to say it certainly helped me understand the Thickbox code (which was my initial reason for reading it). It also showed me some impressive (and/or quirky) features. Here is some of what I found out (drumroll):

Objects:

Everything in JavaScript is an object if it’s not either a number, string, boolean, null, or undefined. Functions, arrays and everything else you can think of are objects – or keyed collections. Objects have prototypes that they can inherit properties from. These prototypes can have prototypes of their own and so on. When we ask for a property on an object, if the object is missing that property then it will delegate to the prototype, then it’s prototype etcetera.

Functions:

Crockford emphasises that functions are “The best thing about JavaScript” (pg 26). Functions in JavaScript are first class objects and it’s for this reason that they can be stored in variables, arrays and other objects. Functions are “used for code reuse, information hiding, and composition.” (pg 26). What is most interesting for me about these is what Crockford describes as the four function invocation patterns, which differ in how the this parameter is initialised:

1. The Method Invocation Pattern: The function is a property of an object. The this parameter gives access to the object that the function belongs to, for example:

var calendar = {
    monthsPerYear: 12,
    currentDate: new Date(),
    currentMonth: function () {
       return this.currentDate.getMonth() + 1;
    },
    monthsToYearEnd: function () {
       return this.monthsPerYear - this.currentMonth()
    }
};

2. The Function Invocation Pattern: If object X has a function which in turn has an inner function, the inner function will have a this parameter that is bound to the global object (yikes). We can give the inner function access to object X by using another variable called that:

calendar.daysToYearEnd = function() {
    var that = this;
    var daysToYearEnd = 0;

    var daysToMonthEnd = function(startDay, month) {
        switch (month) {
        case (9):
        case (4):
        case (6):
        case (11): //Note that Crockford does put switch fall throughs in the JavaScript 'bad' category
            return 30 - startDay;
        case (2):
            return 28 - startDay;
        default:
            return 31 - startDay;
        }
    };

    var daysToEndofCurrentMonth = function() {
        return daysToMonthEnd(that.currentDate.getDate(), that.currentMonth());
    };

    daysToYearEnd += daysToEndofCurrentMonth();
    for (i = 1; i < this.monthsToYearEnd() + 1; i += 1) {
        daysToYearEnd += daysToMonthEnd(0, this.currentMonth() + i);
    }
    return daysToYearEnd;
};

3. The Construction Invocation Pattern: The function is invoked using the new prefix and actually creates a new object. The this parameter is set to the new object. The constructor function has a prototype. The created object (in this case myCalendar) will have its prototype set as the prototype of the constructor function (PersonalisedCalendar.prototype).

var PersonalisedCalendar = function(name) {
    this.name = name;
};

var myCalendar = new PersonalisedCalendar('Liz');

PersonalisedCalendar.prototype.OwnersName = function() {
    return this.name;
};
document.writeln(myCalendar.name)

4. The Apply Invocation Pattern: The apply method lets us decide on the value that should be bound to the this parameter, as well as letting us define an array of parameters:

var today = function() {
    return this.currentDate;
}
var dateToday = today.apply(calendar, null);

More functions… closures and memoization

JavaScript variables have function scope (as opposed to block scope in Java for example). In the earlier example we saw that it was possible for an inner function to access to the variables of an outer function. The inner function will keep a hold on these variables and can continue to use them even if the outer function returns. This website has some good examples of closures – including number 5, which is very similar to one in the book.

We can use closures to help remember the result of previous invocations in order to cut down on the number of times they are called. This called memoization and involves an array to store the calculated results, as well as an inner function. The example the Crockford gives is reproduced (from pg 44/45 of the text) below:

var fibonacci = function() {
    var memo = [ 0, 1 ];
    var fib = function(n) {
        var result = memo[n];
        if (typeof result !== 'number') {
            result = fib(n - 1) + fib(n - 2);
            memo[n] = result;
        }
        return result;
    };
    return fib;
}();

for ( var i = 0; i <= 10; i += 1) {
    document.writeln(fibonacci(i));
}

JSLint

In the text Crockford discusses JSLint – a JavaScript syntax checker and verifier that he’s created. I used it on the code I wrote for this post and it did help identify some missing semi-colons!

Written by lizdouglass

January 21, 2009 at 10:56 am

Posted in Uncategorized

Tagged with