Blog of Jeff A blog about programming and random other things.

26Oct/09link

“Brief” Guide to JavaScript – Part 10

Yes, this is no longer becoming brief; so check out the growing list of previous parts:

Objects Revisited

Objects are the core of JavaScript, so I'm going to a bit further in-depth than previously mentioned. I didn't say explicitly, but everything is JavaScript is an object, booleans, strings, numbers, arrays, functions, etc. are all objects. Before we talk further, I want to quickly review some terminology of objects:


myobj = {}; // constructor that creates an object;             // In this case, an empty object.
myobj.property; // accessing a property
myobj.method(); // calling a function which belongs to an object, aka a method.
// we can also access properties, methods, and references using the// array-styled notation
myobj['property']; // 'property' is called a key
myobj['method'](); // 'method' is the key
myobj['anotherobj']; // 'anotherobj' is the key

References

In contrast to what I initially explain, variables store references to objects. This is slightly different than simply storing data. I feel diagrams explain this the best. Say we do something like this:


var myobj = {'hello': 'world'};
var myobj2 = myobj;

JavaScript engines store the data similar to this:

This means if we change our object, the changes are visible through other variables:


myobj.hello = 'jk';
alert(myobj2.hello); // displays 'jk'

To truly copy an object, we have to manually copy every property:


var myobj2 = {};
for(var p in myobj){
    myobj[p] = myobj[p];
}

This assumes that all the properties don't contain their own properties (like an array). Changing the property or variable changes where that property/variable points to. So:


var myvar = true;
var myvar2 = myobj;
myvar = false;

Which produces something like this:

In simplest terms, you can change where the variable points to, but setting one equal to another will share the same data source. This behavior also apply to function parameters. The rule of thumb is: for objects (those you use {}), arrays, and anything created with a new keyword behave as references.

Reflection Basics

Reflection is a programming terminology which a program that is aware of itself (not in the skynet terms): knowing the existence of variables, functions, or properties. This is particularly easy in JavaScript due to array-styled notation:


var css = ['borderColor', 'backgroundColor'];
var el = document.getElementById('header');
for(var style in css){
    el.styles[style] = 'transparent'; // remove colors.
}

A bit more practical example is when creating similar functions:


var names = {
    'Height': 'height',
    'Width': 'width',
    'Bgcolor': 'backgroundColor',
    'Color': 'color',
    'Size': 'fontSize'
};

for(var fnName in names){
    (function(n){
    window['set'+n] = function(element, value){
        element.styles[names[n]] = value;
    };
    })(fnName);
}
// test it
setColor(document.getElementById('header'), 'red');

As you can see, we can use variables outside our anonymous functions, but you have to beware when the variable is updated in a loop. This is because the function will use the value of the variable at the time of the function call. So after the for loop finished, fnName will be 'Size' and all our functions would be change the 'fontSize' element.

To quickly resolve this, we simply create an anonymous function that accepts the fnName variable. With function calls, non-referenced variables are duplicated (remember: arrays, objects, or things using new are references), so we can use that variable when it was during the function declaration, inside the loop.

This outer scoping of variables is called dynamic scoping, where the values are based on when you call the functions, not when the function was defined.

Classes

Once you start writing larger and larger JavaScript-based applications, you'll may opt to use a more Object-Oriented approach. Classes help provide a "blackbox" approach to stateful widgets/systems. I'm not going to write a lengthy discussing the pros & cons, arguing isn’t my cup of tea ;)

If you haven't used classes much, I'll quickly review some terminology:

  • Property: A variable "about” the object. Think of a characteristic/trait of a particular object: like the box’s color – color would be the property. Identical to properties in object definitions.
  • Method: A name for functions that belongs to a class. Other words, properties that are functions.
  • Class: A "blueprint." Classes define properties and methods. For example: a class would be the architecture's design for a house.
  • Instance: A representation of the "blueprint". Instances can have different values for properties. Continuing our example: An instance would be an actual house. One instance could be blue (property color = blue) and another instance could be red.
  • Static: Treats the class almost like a namespace. Static properties and methods can be access directly. Unlike regular properties and methods, the static variants can't access the currently operating instance because they don't exist in an instance.

Since JavaScript is a bit unusual for classes, which we'll cover shortly.

Instantiated Classes

So we need to define some classes before we create instances of them. JavaScript classes can be created via functions:


function Person(){
}

Seems like a useless function definition, but this is our bare-minimal class definition! We can instantiate the almost useless class:

var john = new Person;

If you've used Object-Oriented programming in other languages, this is absolutely useless. But in JavaScript, properties can be created after the class has been instantiated.

john.name = "John Doe"; // works.

Why? Class instantiations are identical to creating objects. See these:


var myobj = {};
var myobj2 = new Object; // identical
var myobj3 = new Person; // our class is the same

Although you should use the former over the other alternatives. To make our class a bit better before, let's redefine our person class:


function Person(name, phone){
    this.name = name;
    this.phone = phone;
}
var john = new Person('john doe', '123 456 7890');
alert(john.name);
alert(john.phone);

Here we utilize our handy this variable which allows us to set properties and methods which we can access when we instantiate the class. The function parameters act as a constructor, which provides some values we can use when instantiating a class.

Of course we can make it more complex; let's add a method:


function Person(name, phone){
    this.name = name;
    this.phone = phone;
    this.shout = function(){
        alert('hello! My name is ' + name);
    }
}
var john = new Person('john doe', '123 456 7890');
john.shout(); // alerts ‘hello! My name is john doe’

Just like any JavaScript object, just easier to replicate using instances.

Static Classes

Unlike instances, static classes don't require instantiation. Static classes are basically single-instanced classes. The easiest way is to simply define them like namespaces (see previously). But if you want a class to have both static and dynamic properties, simply create the dynamic first:


function Person(name, phone){
    // dynamic-class code
    this.name = name;
    this.phone = phone;
    Person.count++; // modifying our static property
}
Person.count = 0; // static property

Why does this work? Because everything are objects in JavaScript, including functions.

Prototypes

If you haven't noticed, there's one problem with the whole instantiated thing see:


function Person(){}
var john = new Person;
john.walkSpeed = 100;

If we wanted all person instances to have the walkSpeed property, we would need to add that property to all instantiated person classes. Not cool. To resolve this, we can use the special property in all objects: prototype. This allows us to assign properties to all instances of our class.


function Person(){}
var john = new Person;
Person.prototype.walkSpeed = 100;
alert(john.walkSpeed); // prints 100
var joe = new Person;
alert(joe.walkSpeed); // prints 100
john.walkSpeed = 10; // only affects john, poor fellow.

Using prototypes, we can implement like traditional object oriented inheritance.


function Person(){ }
function Employee() {}
Employee.prototype = new Person();

If you are observant, you'll notice we have a restriction: the constructor has to have no parameters. Unfortunately, achieving good prototype-based inheritance with constructor-supported inheritance is a tougher problem (out of scope of this article). I'll direct you here for a do-it-yourself implementation or JavaScript frameworks: prototype & mootools are good OO frameworks.


This wraps up this lengthy week. Next up is the trendy AJAX stuff. Oh boy!

  • Share/Bookmark
11Oct/09link

“Brief” Guide to JavaScript – Part 9

Finally, another part. If you haven’t already, check out the previous parts of this series:

Trying and Catching

Tries & catches are identical to exceptions in other programming languages. If you're not familiar with exceptions & handling them, let's review now. In general purpose programming, errors (aka, exceptions) are thrown for unreliable operations: the network may drop, insufficient permissions, a file is missing, etc. The programming language will generate these exceptions for us, but we can also create our own exceptions if need be.

When an exception is thrown, it halts the executing code and bubbles up out of code blocks (for loops, while loops, if statements, functions, etc.) until it reaches a try block. If caught by a try block, the subsequent catch block is executed. If no try block exists, the exception terminates the execution of the program/script entirely.

In a nutshell, try/catch blocks allow us to handle code that may potentially fail. This is made more useful in many dynamic languages, where exceptions are thrown from almost any error: from stack overflows to accessing a non-existent variable.

But in JavaScript, exceptions are less useful since most of JavaScript relies on generated content: the DOM tree and browser-provided functions. Nonetheless, some browser functions will throw exceptions if they fail. Raised exceptions that are not in a try/catch block are handled by the browser (usually by being display to the JavaScript debugger/console) and the script halts execution.

Let's see some concrete examples:


// result: this code will always show the alert (since we always throw an exception) 
// but normally it isn't guaranteed that exceptions are thrown. 
try {
    throw "Oh noes!";
}
catch(error){ // error contains "Oh noes!" 
    alert(error);
}


Here we simply throw our own exception in our try/catch block. Throw accepts any data to pass to a catch block. Unlike custom exceptions, language-based exceptions' data varies from browser to browser and shouldn't be relied upon.

DOM Ready Event

After using the load event you may have noticed that your JavaScript executes only after everything finishes loaded (which includes images, flash, ads, etc.). We may have a 200-megabyte image on the page (just pretend at least), the JavaScript won't run until that image is finished downloaded by the browser: Not ideal.

We can solve this using the DOM Ready Event. But we should talk a bit about the aforementioned solution I put earlier: simply placing your script tags at the bottom.

The browser creates the DOM tree as the HTML is parsed by the browser. This means any JavaScript code is executed as soon as it is reached by the browser, and giving access to the partially-completed DOM tree it has built. If we place our scripts at the bottom of the page, the entire DOM tree has been built before our scripts execute: which is perfect.

Putting scripts at the bottom also provides a nice side-effect as mentioned on Yahoo!. They speed up loading of your pages and allows the browser to render the page as it parses it (think of how a stereotypical page loads on 56k). This is opposed to freezing other downloading files and providing a blank page until the entire page downloaded and completely parsed when you place script tags in your head.

But sometimes it's useful the place script in head, they don't interfere with your DOM tree manipulations (most of the time) if they're in head as opposed to body. Also, since the page isn't displayed yet, you can hide an element (in conjunction with DOM Ready) before it's displayed. If you placed the script at the bottom, the user could be trying to interact with some elements you didn't want visible while the page is loaded since the browser didn't get to the scripts which hides the element.

For DOM Ready, most browsers support the DOMContentLoaded event which works as intended. But the pesky IE needs an alternative solution, via readystatechange, which can report when the status of an object changes, like when it finishes loading.

But the timing of readystatechange isn't reliable, it can also occur after load. A better method constantly try to use certain functions that IE only provides when the DOM tree is ready.

And here's the monstrosity, commented for understandability.


var isReady = false;
// list of all functions that should be called when DOMReady is achieved.
var readyFunctions = [];
// this is called when the DOM is ready and all functions that
// want to execute when  the DOM is ready (stored in
// readyFunctions) are called. 
function ready(){
    // this will be called multiple times during a load, but we only
    // want its effects once 
    if(!isReady){
        isReady = true;
        for(var i=0; i<readyFunctions.length; i++){
            readyFunctions[i]();
        }
    }
}
// attach our event listeners for the DOM Ready event
if(document.addEventListener){
    // covers all cases (frames & non-frames) for FF2+, Safari 3+, Chrome,
    // Opera 9+ 
    document.addEventListener('DOMContentLoaded', function(){
        document.removeEventListener('DOMContentLoaded',
                                     arguments.callee, false);
        ready();
    }, false);
} else if (document.attachEvent){ // good old internet explorer 
    // works well with frames for IE, but sometimes maybe called *after*
    // the load event. 
    document.attachEvent('onreadystatechange', function(){
        // check it's the right state we're looking for 
        if(document.readyState === 'complete'){
            document.detachEvent('onreadystatechange',
                                 arguments.callee);
            ready();
        }
    });
    // do this only if IE (by checking for element.doScroll) and
    // is not a frame 
    if(document.documentElement.doScroll && window == window.top){
        // this is a recursive anonymous function that
        // is executed immediately 
        (function(){
            // if load got called before we detected it, terminate
            if(isReady) return;
            try {
                // try to use doScroll, which throws an exception
                // if DOM tree isn't ready yet. 
                document.documentElement.doScroll('left');
            } catch (error){
                // catch the exception and try again (recursive
                // call to anonymous function again) 
                setTimeout(arguments.callee, 0);
                // ensures we don't call ready() below when the DOM
                // tree isn't really ready.
                return;
            }
            ready(); // we didn't get an exception, fire ready function.
        })();
    }
}
// if all else fails. For simplicity, the onload property
// is used instead of attachEvent/addEventListener. 
window.onload = ready;

Note: I'm basing my example code from code from jQuery, which also utilizes the IE trick documented here.

Theoretically, you could tidy the code a bit better, but it's usable. This should be before all your regular code. To make some code execute immediately after the DOM tree is loaded simply added your functions to the readyFunctions array:


readyFunctions.push(function(){
    // usually DOM manipulation or attaching events go here. 
    alert('dom is ready!');
}); 

In this case, the alert box will be displayed when the DOM tree is finished, before all the images and flash are loaded.

Namespaces

Let's assume we have two JavaScript developers: Jim and Sammy. Jim writes a function addItem, which handles adding a new item to the inventory. Sammy writes a function, also called addItem, which handles adding a new item to a customer's shopping cart. There's a conflict since a program won't know the difference between addItem that Jimmy wrote versus Sammy.

Namespaces is a solution to this problem by essentially prefixing a set of variables & functions.

In JavaScript, namespaces are simply global objects that contain your functions and variables.


var hui = {
    alert_value: 'hello world!',
    createElement: function(){
        var div = document.createElement('div');
        document.body.appendChild(div);
        alert(hui.alert_value);
    }
};
// call through our namespace: 
hui.createElement(); 

But this can be annoying since we have to refer to the namespace whenever we want to use a function or variable. In addition, any inter-function variables are publicly visible. A better alternative is to wrap everything in an anonymous function:


(function(){
var alert_value = 'hello world!';
function createElement(){
        var div = document.createElement('div');
        document.body.appendChild(div);
        alert(alert_value); // local variable 
};
window.hui = {
    alert_value: alert_value,
    createElement: createElement
};
})();
// call through our namespace: 
hui.createElement();

Like any regular functions, the anonymous function here provides its own scope which hides any local variables. After we have defined our functions and variables, we can then create an object in the window object (the global namespace) with the exact functions and variables we want publicly available.

While you may not use namespaces when writing for a specific page, this is definitely more useful when writing your own framework or portable/reusable code.


Yes, I’ve been slacking (but coursework is a good excuse! Honest!) Besides this, I was thinking of migrating towards screencasts (screenr / jing) instead of just text-based tutorials. I feel those would be easier to churn out, in theory.

Next up: Objects Revisited.

  • Share/Bookmark
25Aug/09link

“Brief” Guide to JavaScript – Part 8

Finally, another part. If you haven’t already, check out the previous parts of this series:

Advanced Topics

Finally, I can stop pushing off things I want to talk about. :) Here’s where I’ll talk about them.

Apply This Call (ordered for pun)

Now we’ll demystify the this variable. This is to represent the object that "owns" the function being called. This is easily shown by an event handler example:

// yes, the "bad" way, we'll talk why later.
document.getElementById('mylink').onclick = function(){
    alert(this.innerHTML);
};

Here we get the innerHTML of the element. For events, this is target/srcElement. This is preferred for its simplicity. Using this, we can also do something like:

function myhandler(){
    this.style.color = 'red';
}
for(var el : document.getElementsByTagName('p')){
    el.addEventListener('click', myhandler, false);
}

This will make the text of any p element red when the user click on it. This saves us time from having to write functions for each element.

Of course there's a caveat, IE's attachEvent sets this to the window object, making the above code useless in IE (even if you converted addEventListener appropriately). Your wrapper for adding events can change this with the next two handy functions: apply and call.

Apply and call executes a function with a provided this object and set of parameters. The only difference between the two is that apply accepts an array as the parameter list instead of call, which you pass parameters in directly.

function customFn(param1){
    alert('this = ' + this);
    aert('param1 = ' + param1);
}
// all three calls are identical
customFn('hello'); // always implies this = window object
customFn.call(window, 'hello');
customFn.apply(window, ['hello']);

This is handy when you need to assign a bind a different value to this for a function. In a way, this allows you to provide custom scoping to a particular function. Class-styled JavaScript frameworks use this to refer to the class (for methods).

Using the above myhandler function, we can pass a custom this, and the function wouldn't care that it wasn't called via an event:

myhandler.call(document.getElementById('my_element'));

Optional parameters

Undefined Parameters

This isn't quite new, but due to the nature of || and && (returning the truthy statement), we can use it as a rudimentary optional parameter feature:

function myfn(optional){
    var param = optional || 'my default';
    // use param (hopefully more useful than this) 
    return param;
}
// examples 
myfn(); // optional variable is undefined; returns 'mydefault' 
myfn('hello'); // optional variable is 'hello'; returns 'hello' 
myfn(false); // optional variable is false; returns 'mydefault'

The reason why this works is because any parameters not filled are automatically set to undefined, which is falsy to ||. The caveat about this method if we expect a boolean value. A false value will fill a default, so we have to check for undefined explicitly. This is only necessary if we want to accept boolean or integer values.

function myfn(optional){
    var param;
    if(optional === undefined){
        param = 'default';
    } else {
        param = optional;
    }
    // commented line below is same as above code;
    // var param = (optional === undefined) ? 'default' : optional;
    return param;
}
// examples 
myfn(); // returns 'default' 
myfn('hello'); // returns 'hello' 
myfn(false); // returns false
Variable Parameter Length

Sometimes we want to have a variable number of parameters, we can build a rudimentary clone of sprintf, or python's % operator on strings (changed to format in python 3). We'll only accept %s to represent a variable to replace with and a variable number of parameters which represents the values to replace it with.

To do this, we can use the special arguments array variable provided to functions which provides meta information about the specific function call. Each element in the array represents a parameter.

function sprintf(){
    var str = arguments[0]; // our string
    for(var i=1; i<arguments.length; i++){
        // replaces first occurrence of %s to the given parameter
        str = str.replace('%s', arguments[i]);
    }
    return str;
}
// usage: 
sprintf("hello %s", "john"); // returns "hello john" 
// returns "the sum of 1 and 2 is 3"
sprintf("the sum of %s and %s is %s", 1, 2, 1+2);

Besides parameters, we've used arguments.callee to refer to the current function being executed, which is handy for anonymous function recursion.

// recursive anonymous function that displays a predefined countdown using alerts. 
var num = 3;
(function(){ // count down     alert(num);     num—;
    if(num < 1){ return; }     setTimeout(arguments.callee, 0);
})();
Object-based Optional Parameters

Both optional parameter methods we listed so far have their drawbacks if you have multiple optional parameters. Say we have this theoretical function:

function createRobot(unique_id, name, greeting_message, goodbye_message){
    // unique_id is required, rest are optional parameters 
    var name = name || 'unknown robot';
    var greeting_message = greeting_message || 'hello, human!';
    var goodbye_message = goodbye_message || 'destroy all humans!';
}

It's nice, but what if we wanted to only have a custom goodbye message? We would have fill undefined for the other parameters. If this function changes (say, another optional parameter is inserted between name and greeting_message), we have to change all our calls too. A better way would be to accept an optional object at the end.

function createRobot(unique_id, options){
    var name = options.name; // options.name and options['name'] are identical 
    var greeting_message = options.greeting_message;
    var goodbye_message = options.goodbye_message;
}

The main problem of the implementation above is handling if options parameter didn’t have a specific key we're looking for. So we need to internally hold an object with default values. Then we iterate over the passed options object and replace any default values with the new one like so:

function createRobot(unique_id, options){
    // default values 
    var opt = {
        name: 'unknown robot',
        greeting_message: 'hello, human!',
        goodbye_message: 'destroy all humans!'
    };
    // set options to {} if no value was provided
    options = options || {};
    for (var key in options){
        opt[key] = options[key];
    }
    var name = opt.name;
    var greeting_message = opt.greeting_message;
    var goodbye_message = opt.goodbye_message;
    // do robot stuff. 
}
// examples: 
createRobot('ufo-117');
createRobot('healer-93', {goodbye_message: 'Have a good day!'});
createRobot('sn-131', {name: 'skynet', greeting_message: 'Useless human!'}); 

As you can see, this provides us flexibility for how many and which specific optional parameters we want to fill. Most javascript frameworks extract this functionality out for simplier use, we can do the same:

function defaultOptions(defaulted, provided){
    defaulted = defaulted || {};
    provided = provided || {};
    for (var key in provided){
        defaulted[key] = provided[key];
    }
    return defaulted;
}
// usage 
function createRobot(id, options){
    var opt = {
        name: 'unknown robot',
        greeting_message: 'hello, human!',
        goodbye_message: 'destroy all humans!'
    };
    opt = defaultOptions(opt, options);
    // we can access the options in the opt object. 
} 

Our implementation doesn't handle deep copying to ensure the returned object isn't inadvertently changed, which most JS frameworks handle, but for this use case, it's not a deal-breaker. In JavaScript, this is the preferred way to handle multiple optional parameters.


And that wraps up this week. Next will be Try/Catch, DOM Ready, and Namespaces.

  • Share/Bookmark

Recent Posts

Topics

Archives

Following

Links