This book assumes that you've done at least a mild amount of web development with client-side technologies such as HTML, JavaScript, and CSS. You by no means, however, need to be an expert in any of these skills and you really don't need to know anything at all about what happens on a web server because Dojo is a client-side technology; merely having dabbled with them enough to know what they are and how they are used is more than enough.
If you are an existing web developer or even a hobbyist who is able to construct a very simple web page and apply a dab of JavaScript and CSS to liven it up a bit, then you should definitely keep reading. If you haven't even heard of HTML, JavaScript, or CSS, and have never done so much as written a line of code, then you might want to consider picking up a good introduction on web development as a supplement to this book.
With regard to development tools, although you could use your favorite text editor and any web browser to do some effective development with Dojo, this book makes frequent references to Firefox and the wonderful Firebug add-on that you can use to debug and deconstruct web pages as well as tinker around with JavaScript in its console. Although you could use Firebug Lite with another browser like Internet Explorer, the full version of Firebug is vastly superior and you won't be disappointed by it. (In general, a practice that's commonly accepted is to develop with Firefox using Firebug, but test frequently with IE.) You can get Firefox and Firebug from http://getfirefox.com and http://getfirebug.com, respectively.
Two other tools you may want to consider for Firefox are Chris Pederick's Web Developer Toolbar, available at http://chrispederick.com/work/web-developer/, which provides some additional tools that are useful during development, and the Clear Cache Button Firefox add-on, available at https://addons.mozilla.org/en-US/firefox/addon/1801, which is a button for your toolbar that you can use to quickly clear your cache. Occasionally, it can be the case that your browser may "act up" and serve you stale content; clearing the cache sometimes helps.
Closures, context, and anonymous functions are some of the most important fundamental concepts in JavaScript, and because mastery of the toolkit involves more than a casual understanding of these topics, this section is worth a careful read. Even though it may sound like advanced material, these concepts are essential to mastering the JavaScript language and really understanding some of the underlying design within the toolkit. You could try and pick up this knowledge as you go along, but if you spend a little bit of time up front, you'll find that many selections from the ensuing chapters are considerably easier to understand.
A closure is essentially the coupling of data elements and the scope that contains (or encloses) that data. Although typical situations involving a single global scope that contains some functions are fairly straightforward, nested functions have the ability to really change things up. To illustrate, consider Example 1.
Example 1. Minimalist illustration of closures
function foo( ) { var x = 10; return function bar( ) { console.log(x); } } var x = 5; var barReference = foo( ); barReference( ); //What gets printed? 10 or 5
Depending on your programming background, the previous code
snippet might actually surprise you. As it turns out, the value
10
is printed to the screen
because, in JavaScript, the entire scope chain is taken into account
when evaluating a function. In this case, the scope chain that is
returned is associated with bar
,
which is returned from evaluating foo
. Thus, when barReference
is evaluated, the value for
x
is looked up on the fly, and is
tracked down in the body of foo
.
This is directly contrary to many programming languages, which would
look up the context in the most immediate scope.
Tip
In JavaScript, functions are "first-class" objects that you can pass around, assign to variables, etc., and many of Dojo's design patterns leverage this characteristic heavily.
Although JavaScript closures are normally considered an advanced topic, the sooner you have a firm grasp on closures, the sooner you'll be on your way toward mastering the language and the better you'll understand many pieces of Dojo's design philosophy. In practical terms, that means you'll be more productive, able to track down tricky bugs a lot faster, and perhaps even become a more interesting person. (Well, two out of three isn't bad.) Consult David Flanagan's legendary JavaScript: The Definitive Guide (O'Reilly) for an excellent analysis of closures.
JavaScript's extreme dynamism equips it with tremendous
flexibility, and one of the most interesting yet least understood
facets of its dynamism involves context. You
probably already know that the default this
context for browser-based JavaScript
is the global window
object. For
example, the following statements should evaluate to true
for virtually every browser
implementation:
//the default context for a document is the window console.log(window ==this); //true //document is a shortcut for window.document console.log(document == window.document); //true
With respect to Function objects, the keyword this
is specifically used to refer to its
immediate context. For example, you may have seen this
used in a JavaScript Function object
somewhat like the following:
function Dog(sound) { this.sound = sound; } Dog.prototype.talk = function(name) { console.log(this.sound + "," + this.sound + ". My name is", name); } dog = new Dog("woof"); dog.talk("fido"); //woof, woof. my name is fido
If you come from Java or a similar object-oriented background,
the way that sound
is looked up
relative to the current object probably seems familiar enough.
Nothing interesting is happening yet. However, matters can get more
complicated if you bring in the built-in call
function. Take a moment to study the
following contrived example that introduces the call
function at work:
function Dog(sound) {
this.sound = sound;
}
Dog.prototype.talk = function(name) {
console.log(this.sound + "," + this.sound + ". my name is", name);
}
dog = new Dog("woof");
dog.talk("fido"); //woof, woof. my name is fido
function Cat(sound) {
this.sound = sound;
}
Cat.prototype.talk = function(name) {
console.log(this.sound + "," + this.sound + ". my name is", name);
}
cat = new Cat("meow");
cat.talk("felix"); //meow, meow. my name is felix
cat.talk.call(dog, "felix") //woof, woof. my name is felix
Whoa! That last line did something pretty incredible. Through
the cat
object instance, it
invoked the talk
method that is
bound to the cat
prototype and
passed in the name
parameter to
be used as usual; however, instead of using the sound
that is bound to cat
's this
, it instead used the sound
value that is bound to dog
's this
because dog
was substituted in for the
context.
It's well worth a few moments to tinker around with the
call
function to get more
comfortable with it if it's new to you. In many less dynamic
programming languages, the ability to redefine this
would almost be ludicrous. As a
potent language feature, however, JavaScript allows it, and toolkits
like Dojo leverage this kind of inherent dynamism to do some amazing
things. In fact, some of these amazing things are coming up in the
next section.
Tip
Although the intent of this book isn't to provide exhaustive
JavaScript language coverage that you could read about in
JavaScript: The Definitive Guide, you may
find it instructive to know that apply
is a function that works just like
call
except that instead of
accepting an unspecified number of parameters to be passed into
the target function, it accepts only two parameters, the latter
parameter being an Array
, which
can contain an unsaid number of values that become the built-in
arguments
value for the target
function. Essentially, you'll choose the one most convenient for
you.
In JavaScript, Function objects may be passed around just like any other type. Although using anonymous functions inline can definitely provide some syntactic sugar that reduces the clutter and makes code more maintainable, a perhaps more significant feature of anonymous functions is that they provide a closure that protects the immediate context.
For example, what does the following block of code do?
//Variable i is undefined. for (var i=0; i < 10; i++) { //do some stuff with i } console.log(i); // ???
If you thought that the console
statement prints out undefined
, then you are sorely mistaken. A
subtle but important characteristic of JavaScript is that it does
not support the concept of blocked scope outside of functions, and
for this reason, the values of i
and any other "temporary" variables defined during iteration,
conditional logic, etc., live on long after the block
executes.
If it's ever prudent to explicitly provide blocked scope, you could wrap the block inside of a Function object and execute it inline. Consider the following revision:
(function( ) { for (var i=0; i < 10; i++) { //do some stuff with i } })( ) console.log(i); // undefined
Although the syntax is somewhat clumsy, keeping it clear of artifacts can sometimes prevent nasty bugs from sneaking up on you. Many Base language functions introduced in the following chapters provide closure (in addition to syntactic sugar and utility) to the code block being executed.
Get Dojo: The Definitive Guide now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.