« December 2005 | Main | February 2006 »
Window object
NYTimes has a good article on the Samsung A900 ("Blade") vs the Moto RAZR. An OO approach is a key part of your Javascript/Ajax programming arsenal. There are multiple ways to program Javascript in an object-oriented way. The Prototype library adds some helper constructs to facilitate object orientation, as do many other Javascript libraries. Regardless of which framework you use (or if you choose to use none at all), an object-oriented approach can make your Ajax programming easier.
Here, I'm demonstrating a basic syntax for OO; you can use this syntax literally, or use it to enhance your understanding of the various framework-based OO approaches available out here.
// a Person class
function Person (sName, nAge) {
this.sName = sName;
this.nAge = nAge;
}
// add a method to the class by adding a function to its prototype
Person.prototype.tellMe = function() {
return ("My Name is "+this.sName+". I am "+this.nAge+" years old");
}
That's all there is too it. You have now defined a class (Person), with one method (tellMe).
var oPerson = new Person("Bob", 28);
alert (oPerson.tellMe());
. . . will give us:
You can model inheritance and more with Javascript. A good place to learn more is webreference's Object-Oriented Programming with JavaScript series.
String.prototype.trim = function () {
var sNew = this.replace(/^\s*/, ""); // strip whitespace from the beginning of the string
sNew = sNew.replace(/\s*$/, ""); // strip whitespace from the end of the string
return sNew; // return the mutated string
}
You can call the method on any instance of string:
var sString = "a value from an HTML form . . . "; sString = sString.trim();
Everything in Javascript has a prototype. Any functions you add to the prototype are automatically available to each and every instance of the class. Accessing the prototype is as easy as specifying [class].prototype. So in the example above, we added a function (trim) to string's prototype: string.prototype.trim=function(){...};
The other key is the "this" keyword. Whenever you are coding a "prototype" function, you need access to the particular instance. The "this" keyword lets you do it. At runtime, the "this" keyword resolves to the actual instance of the object, in this case a String.
Note that this example does not mutate the string on which you called the method. Rather, it returns a new string with whitespace removed. The original instance is left unchanged. If you were to do the following:
var sString = " a value from an HTML form . . . "; sString.trim();
. . . sString would not change. Calling the trim() method would produce a new string, which would then be thrown away because it isn't being assigned to anything.
function doSomething (sWhatever, oOptions) {
var oOptions = augment({
sOptOne: "foo",
bOptTwo: false
}, oOptions );
// sWhatever is a regular argument. We assume it's always going to be passed
alert(sWhatever);
// sOptOne and bOptTwo are optional;
// they are defaulted to "foo" and false, respectively
alert(oOptions.sOptOne);
alert(oOptions.bOptTwo);
}
The function defined above can be called in a number of different
ways:
The key here is that the optional arguments are specified by name, rather than position. Therefore, you can leave any of them out, and they assume the default value you specified in the function itself.
The "augment()" function is what makes it all happen. This function takes two or more objects, and augments the first object with properties from the second (or subsequent, of you pass more than one) object(s).
For defaultable arguments, the first object is the default values ( that's the {sOptOne: "foo", bOptTwo: false} part, and the second object is the oOptions object passed into our function.
Here is the augment function:
/*
Augment an object by replacing its key:value pairs with those
from other object(s), and adding pairs from other object(s) that don't
exist in you. Key:value pairs from later objects will
overwrite those from earlier objects.
If null is given as the initial object, a new one will be created.
This mutates and returns the object passed as oSelf. The other objects are not changed.
*/
function augment (oSelf, oOther) {
if (oSelf == null) {
oSelf = {};
}
for (var i = 1; i < arguments.length; i++) {
var o = arguments[i];
if (typeof(o) != 'undefined' && o != null) {
for (var j in o) {
oSelf[j] = o[j];
}
}
}
return oSelf;
}
Optional, defaultable arguments are a powerful Javascript programming technique. They make it much easier to evolve your code, especially when you build "visual" objects -- objects that correspond to visual elements on the page.
if (document.all) { // very basic browser detection
var sFloat="styleFloat"; //ie
} else {
var sFloat="cssFloat"; //firefox
}
var oMyDiv=document.getElementById("myId");oMyDiv.style[sFloat]="left";
try {
var foo = somethingRisky();
} catch (e) {
jslog.error("Something risky failed! foo="+foo+"; error is "+e.message);
}
