Dojo: the JavaScript Toolkit with Industrial-Strength Mojo
JavaScript is an object-oriented programming language, but unlike the class-based languages of Java or C++, it uses prototypal inheritance as its mechanism of choice instead of a class-based paradigm. Consequently, mixing properties into object instances as part of a “has-a” relationship is often a far more natural pattern than attempting to mimic class-based patterns that espouse an “is-a” relationship. Consider the following example that adds in a collection of properties to an object instance all at once using dojo.mixin:
var obj = {prop1 : "foo"}
/* obj gets passed around and lots of
interesting things happen to it */
// now, we need to add in a batch of properties...
dojo.mixin(obj, {
prop2 : "bar",
prop3 : "baz",
prop4 : someOtherObject
});
The dojo.extend function works much like dojo.mixin except that it manipulates a constructor function's prototype instead of the specific object instances.
Of course, there are some design patterns that do lend themselves to inheritance hierarchies, and the dojo.declare function is your ticket to mimicking class-based inheritance if you find yourself in a predicament that calls for it. You pass it the fully qualified name of the “class” you'd like to create, any ancestors that it should inherit from, and a hash of any additional properties. The dojo.declare function provides a built-in construction function that gets run, so any parameters that are passed in can be handled as needed. Here's a short example demonstrating a Baz class that multiply inherits from both a Foo and a Bar class:
//create an lj.Foo that doesn't have any ancestors
dojo.declare("lj.Foo", null,
{
/* custom properties go here */
_name : null,
constructor : function(name) {
this._name = name;
},
talk : function() {alert("I'm "+this._name);},
customFooMethod : function() { /* ... */ }
});
//create an lj.Bar that doesn't have any ancestors
dojo.declare("lj.Bar", null,
{
/* custom properties go here */
_name : null,
constructor : function(name) {
this._name = name;
},
talk : function() {alert("I'm "+this._name);},
customBarMethod : function() { /* ... */ }
});
//create an lj.Baz that multiply inherits
dojo.declare("lj.Baz", [lj.Foo, lj.Bar],
{
/* custom properties go here */
_name : null,
constructor : function(name) {
this._name = name;
},
talk : function() {alert("I'm "+this._name);},
customBazMethod : function() { /* ... */ }
});
//parameters get passed into the special constructor function
bartyBaz = new lj.Baz("barty");
When each of the dojo.declare statements is encountered, internal processing leaves a function in memory that can be readily used to instantiate a specific object instance with the new operator—just like plain-old JavaScript works. In fact, the bartyBaz object is one such instantiation. It inherits the customFooMethod and customBarMethod from ancestors, but provides its own talk method. In the event that it had not provided its own talk method, the last one that was mixed in from the ancestors would have prevailed. In this particular case, the ancestors were [lj.Foo, lj.Bar], so the last mixed in ancestor would have been lj.Bar. If defined, all classes created with dojo.declare have their parameters passed a special constructor function that can be used for initialization or preprocessing.
Note
Strictly speaking, there aren't classes in JavaScript—only objects exist. When discussing simulated inheritance situations, however, it is not uncommon to use the word “class” as though classes really do exist, provided appropriate caveats (like this one) are applied.
No discussion of a JavaScript toolkit would be complete without a mention of the AJAX and server-side communication facilities that are available. Dojo's support for server-side communication via the XMLHttpRequest (XHR) object is quite rich, and the dojo.xhrGet function is the most logical starting point, because it is the most commonly used variant. As you might have suspected, it performs a GET request to the server. Unless you configure it otherwise, the request is asynchronous and the return type is interpreted as text. Here's an example of typical usage:
dojo.xhrGet({
url : "/foo", //returns {"foo" : "bar"}
handleAs : "json", // interpret the response as JSON vs text
load : function(response, ioArgs) {
/* success! treat response.foo just like a
normal JavaScript object */
return response;
},
error : function(response, ioArgs) {
/* be prepared to handle any errors that occur here */
return response;
}
});
A point wasn't made of it, but the reason that both the load and error function returns the response type is because Dojo's I/O subsystem uses an abstraction called a Deferred to streamline network operations. The Deferred implementation was adapted from MochiKit's implementation (which was, in turn, inspired from Python's Twisted networking engine). The overarching concept behind a Deferred is that it provides a uniform interface that drastically simplifies I/O by allowing you to handle asynchronous and synchronous requests the very same way. In other words, you can chain callbacks and errbacks arbitrarily onto a Deferred, regardless of whether the network I/O is in flight, threw an Error or completed successfully. Regardless, the callback or errback is handled the same way. In some situations, Deferreds almost create the illusion that you have something like a thread at your disposal.
Here's an updated example of the previous dojo.xhrGet function call that showcases the dojo.Deferred object that is returned:
var d = dojo.xhrGet({
url : "/foo", //returns {"foo" : "bar"}
handleAs : "json", // interpret the response as JSON instead
load : function(response, ioArgs) {
/* success! treat response.foo just
like a normal JavaScript object */
return response; // pass into next callback
},
error : function(response, ioArgs) {
/* be prepared to handle any errors that occur here */
return response; //pass into next errback
}
});
/* The xhrGet function just fired. We have no idea if/when
it will complete in this case since it's asynchronous.
The value of d, the Deferred, right now is null since it
was an asynchronous request */
//gets called once load completes
d.addCallback(function(response) {
/* Just chained on a callback that
fires after the load handler with the
same response that load returned. */
return response;
});
d.addCallback(function(response) {
/* Just chained on another callback that
fires after the one we just added */
return response;
});
d.addErrback(function(response) {
/* Just added an errback that
fires after the default error handler */
return response;
});
/* You get the idea... */
Again, the beauty of a Deferred is that you treat it as somewhat of a black box. It doesn't matter if, when or how it finishes executing. It's all the same to you as the application programmer.
Just so you're aware, sending data to the server with another HTTP method, such as POST or PUT, entails using the very same kind of pattern and works just as predictably with the dojo.xhrPost function. You even can provide a form node so that an entire form is POSTed to the server in one fell swoop or pass in raw data for those times when you need to transfer some information to the server as part of a RESTful (Representational State Transfer-based) architecture. The dojo.toJson function may be especially helpful in serializing JavaScript objects into a properly escaped JSON string, if the protocol is something along the lines of a JSON-RPC system in which the envelope is expected to be JSON in both directions.
Today’s modular x86 servers are compute-centric, designed as a least common denominator to support a wide range of IT workloads. Those generic, virtualized IT workloads have much different resource optimization requirements than hyperscale and cloud applications. They have resulted in a “one size fits all” enterprise IT architecture that is not optimized for a specific set of IT workloads, and especially not emerging hyperscale workloads, such as web applications, big data, and object storage. In this report, you will learn how shifting the focus from traditional compute-centric IT architectures to an innovative disaggregated fabric-based architecture can optimize and scale your data center.
Sponsored by AMD
Built-in forensics, incident response, and security with Red Hat Enterprise Linux 6
Every security policy provides guidance and requirements for ensuring adequate protection of information and data, as well as high-level technical and administrative security requirements for a system in a given environment. Traditionally, providing security for a system focuses on the confidentiality of the information on it. However, protecting the data integrity and system and data availability is just as important. For example, when processing United States intelligence information, there are three attributes that require protection: confidentiality, integrity, and availability.
Learn more about catching the bad guy in this free white paper.
Sponsored by DLT Solutions
| Making Linux and Android Get Along (It's Not as Hard as It Sounds) | May 16, 2013 |
| Drupal Is a Framework: Why Everyone Needs to Understand This | May 15, 2013 |
| Home, My Backup Data Center | May 13, 2013 |
| Non-Linux FOSS: Seashore | May 10, 2013 |
| Trying to Tame the Tablet | May 08, 2013 |
| Dart: a New Web Programming Experience | May 07, 2013 |
- RSS Feeds
- New Products
- Making Linux and Android Get Along (It's Not as Hard as It Sounds)
- Drupal Is a Framework: Why Everyone Needs to Understand This
- A Topic for Discussion - Open Source Feature-Richness?
- Home, My Backup Data Center
- Developer Poll
- Dart: a New Web Programming Experience
- What's the tweeting protocol?
- New Products
- Web Hosting IQ
1 hour 27 min ago - Thanks for taking the time to
3 hours 3 min ago - Linux is good
5 hours 1 min ago - Reply to comment | Linux Journal
5 hours 18 min ago - Web Hosting IQ
5 hours 48 min ago - Web Hosting IQ
5 hours 49 min ago - Web Hosting IQ
5 hours 49 min ago - Reply to comment | Linux Journal
8 hours 50 min ago - play with linux? i think you mean work-around linux
17 hours 16 min ago - Where is Epistle?
17 hours 22 min ago
Enter to Win an Adafruit Prototyping Pi Plate Kit for Raspberry Pi

It's Raspberry Pi month at Linux Journal. Each week in May, Adafruit will be giving away a Pi-related prize to a lucky, randomly drawn LJ reader. Winners will be announced weekly.
Fill out the fields below to enter to win this week's prize-- a Prototyping Pi Plate Kit for Raspberry Pi.
Congratulations to our winners so far:
- 5-8-13, Pi Starter Pack: Jack Davis
- 5-15-13, Pi Model B 512MB RAM: Patrick Dunn
- Next winner announced on 5-21-13!
Free Webinar: Linux Backup and Recovery
Most companies incorporate backup procedures for critical data, which can be restored quickly if a loss occurs. However, fewer companies are prepared for catastrophic system failures, in which they lose all data, the entire operating system, applications, settings, patches and more, reducing their system(s) to “bare metal.” After all, before data can be restored to a system, there must be a system to restore it to.
In this one hour webinar, learn how to enhance your existing backup strategies for better disaster recovery preparedness using Storix System Backup Administrator (SBAdmin), a highly flexible bare-metal recovery solution for UNIX and Linux systems.




Comments
Shaguf
Hey Guys,
Author of More Servlets and JSP, Marty Hall is coming to Bangalore this April to speak on Choosing an Ajax/JavaScript Toolkit: A Comparison of the Most Popular JavaScript Libraries, Pure Java Ajax: An Overview of GWT 2.0, Integrated Ajax Support in JSF 2.0 and Ajax Support in the Prototype JavaScript Library. You can get more information on developersummit dot com