Although it's not an object-oriented language, JavaScript is an object-based language. This means that, although it might not be as powerful as PHP, Ruby, or Java, it is still pretty darn powerful. Add the fact that it is currently the best/only choice available, and you'll quickly understand why objects are important.
Although there are several ways to create objects in JavaScript, I usually use only two. The first method of creating an object in JavaScript is simply a matter of writing a function and assigning it to a variable using the new operator to create an instance, as shown in Listing 12-1.
Listing 12-1. Example function Class Constructor
function word() {
var _setCount = 0; // Protected variable
this.theWord; // Public property
this.setWord = _setWord; // Public method setWord
this.getWord = _getWord; // Public method getWord
this.count = _getSetCount; // Public method count
function _setWord(theWord) {
// Public exposed as getWord
this.theWord = theWord;
_incrementCount();
}
function _getWord() { // Public exposed as setWord
return(this.theWord);
}
function _getSetCount() { // Public exposed as count
return(_setCount);
}
function _incrementCount() { // Private method
++_setCount;
}
}
var myInstance = new word();
Now we have an instance of the property word assigned to the variable myInstance, and the only question is, how do we use it? Thankfully, the notation for addressing properties and methods is a relatively standard instancename.property or instancename.method(). If you're looking at the constructor, the way to distinguish them is that they are all preceded by the this keyword. The way to tell which are properties and which are methods is that methods always are equal to a function. It is important to point out that the parentheses are omitted because including them would cause the method to be invoked as well as exposed.
Although the previous class constructor is essentially useless, it does show the details of how to create a constructor. It has private members, _setCount, and private methods, _incrementCount. Also, as explained previously, it has both public properties, as in theWord, and public methods, as in setWord, getWord, and getSetCount. Of course, an example that is actually useful might not have all of these.
12.2.1. Collections
I might be wrong, but I am of the opinion that the most useful type of data structure that has ever been conceived, excluding the DOM, is perhaps an associative array. If you're unfamiliar with this type of data structure, information is stored in name/value pairs. If you know the name, you can find the value. And the value isn't limited to any particular data type; come to think of it, neither is the name. A good use would be to cache XSL style sheets because they usually don't change very often. After they're cached, it is no longer necessary to bother the web server to get them; all that is necessary is to retrieve them from the cache. However, there is one danger, and that danger is caching information that shouldn't be cached because someone else might change it, as in the results of database queries.
Listing 12-2 is an example of a constructor for a lightweight cache/associative array. The single private property, _cache, is a JavaScript object that is the cache itself. There are three public methods to handle inserting name/value pairs, retrieving values, and purging either selected name/value pairs or the entire contents of the cache.
Listing 12-2. Cache Class Constructor (Associative Array)
As with the previous example, it is necessary to create an instance of the object before using it. Listing 12-3 shows the object being put through its paces, along with the expected results shown in the comments.
Listing 12-3. Listing Head Here
var magicWords = new Cache();
magicWords.insert(1,'xyzzy'); // Insert key = 1, value = 'xyzzy'
magicWords.insert(2,'plugh'); // Insert key = 2, value = 'plugh'
magicWords.insert(3,'plover');
// Insert key = 3, value = 'plover'
alert(magicWords.names()); // 1,2,3
alert(magicWords.retrieve(1)); // 'xyzzy'
alert(magicWords.retrieve(2)); // 'plugh'
magicWords.purge(3);
// Purge key/value pair - key = 3
alert(magicWords.retrieve(3)); // null
alert(magicWords.names()); // 1,2
magicWords.purge(); // Purge all key/value pairs
alert(magicWords.retrieve(1)); // null
The caching class is pretty straightforward; it is only a wrapper around a JavaScript object that has public methods that allow for changes to the object and retrieval from the object.
12.2.2. XML
Without a doubt, my biggest complaint concerning client-side XML is the lack of a single cross-browser way to create an XML document. This is one of those areas in which cross-browser coding can be a real drag because I have a tendency to create a page using a single browser. Only when I get it working in my browser of choice do I go back and try to make it work for Internet Explorer. In case you are wondering, this makes for some really ugly JavaScript, all sewn together from various mismatched parts. I may be a mad scientist, but there is something to be said for reusability.
That's the reason I cobbled together a few class constructors to neaten things up around the old lab. It's not like I'm using coasters or anything. I'm just trying to make sure that I can understand what I wrote six months from now. They say that the memory is the first thing to goor is it the hair? Whatever, I can't even remember who "they" are anyway, so it can't be important.
The first of these class constructors is to handle the details involved with using the XMLHttpRequest object. It deals with whether the browser is Microsoft Internet Explorer or any other browser, and then it creates the XMLHTTPRequest object using the syntax appropriate to the specific browser. In addition, it handles readyState changes for asynchronous requests. Unlike the previous example, which was created in much the same manner as a regular JavaScript class, this time a prototype object is created. Although they're not used for these constructors, prototypes offer the advantage of allowing for the possibility of inheritance if it is deemed necessary in the future. Listing 12-4 shows what the constructor looks like.
Listing 12-4. Cross-Browser (Gecko and IE) XMLHttp Class Constructor
The constructor shown does exactly what the handwritten code from the beginning of Chapter 8, "AJAX Using XML and XMLHttpRequest," does. In a nutshell, it sends an XMLHttpRequest to the server, waits for the response, and then acts upon the response. This is not a big deal; just create an instance, and it takes care of everythingunless, of course, you're paid by the line.
Now that we've got a constructor to handle the getting of XML, it might be a good idea to figure out a place to put it. What's needed, as if you didn't already know, is a generic XML document object. It doesn't have to be perfect; it only has to workand by "work," I mean offer a single set of properties and methods. From the previous chapters, you're already aware that this is written, so let's take a gander at it in Listing 12-5.
Listing 12-5. Cross-Browser XML Document Class Constructor
Now that there is a generic constructor for XML documents and a constructor for the XSLT Request object, the next task is to ask the nice web service for an XML document. To do this, a quick and easy way of producing a SOAP envelope is required. In writing this constructor, I learned something about SOAP that I hadn't realized in the past: SOAP is, in some ways, like a car. With a car, there is a base model, and, regardless of the options, the base model remains the same. Oh, sure, some cars have better sound systems and some have bigger engines, but underneath all the little extras, the cars are essentially the same. Take my car, for example; with the exception of the dirt and the dent on the hood from a flower pot, when you get past the options, it is just like the other car from that model year.
This same approach was used when writing the SOAPEnvelope constructor. A basic template serves as a starting point, and all of the other options are then added on. These options consist of things such as the operator, content, and namespaceall required, but very often different from request to request. Listing 12-6 shows the inner workings of this constructor.
Listing 12-6. Cross-Browser SOAPEnvelope Class Constructor That Uses Regular Expressions
12.2.3. XSLT
The final constructor that was used in the examples was the XSLTProcessor constructor, which serves as the poster child for code reuse. It has two instances of XMLDocument objects, one for the XML document and one for the XSL style sheet. It also serves fairly well to show some of the difference between Gecko-based browsers such as Firefox, Mozilla, and Netscape, and Microsoft Internet Explorer.
These differences range from Internet Explorer needing a template to create a processor to something as simple as Firefox needing a serializer to obtain the text representation of an XML document. Listing 12-7 shows the constructor for the XSLTProcessor.
Listing 12-7. Cross-Browser XSLTProcessor Class, Used for Transformations
12.2.4. Serialization Without Berries
One common item that you'll notice throughout each of the previous constructors is that serialization plays a big part in handling XML. Several reasons account for this, the first being that XML was designed to be human readable, and humans read text, not binary. For example, when was the last time you heard, "ASCII 65, uppercase 'A'"? I'm the one who was called a mad scientist, and I don't deal with that stuff, so I can't imagine the more mundane members of humanity doing things like that.
The second reason for serialization is the underlying architecture of the web, the Hypertext Transfer Protocol, or HTTP, for short. The HTML, XHTML, JavaScript, CSS, XML, and XSL travel back and forth from the server to the client as text. Without serialization, all of the "X-stuff," as an old supervisor of mine put it, wouldn't be going anywhere.
Another reason for serialization is that, unlike an XML object, very little overhead is associated with text. An XML DOM document requires between three and ten times the memory of the equivalent text document. This overhead could cause some issues in the client's browser on older machines. Of course, the issue of overhead has to be weighted against parsing the text to load a document.
My final reason for serialization is that it is just so easy to load an XML document from a text document. In Microsoft Internet Explorer, it is simply a matter of using the loadXML method. With Firefox, a little more work is necessary, but not too much. Just use the DOMParser's parseFromString method and reconstituted XML, just like freeze-dried coffee or freeze-dried minions.



0 comments:
Post a Comment