Although the global window
object provides the outermost layer of context for a web application,
there may be times when you need to swap out the default context for
another one. For example, you may want to persist the exact state of a
session when the user exits an application, or you might have a custom
execution environment that's already been preconfigured for a
particular circumstance. Instead of having code that manually iterates
over sets of conditions to configure the environment each time, you
might opt to use Base's window facilities to swap out the existing
context for another one.
The following function allows you to change out the dojo.global
object and dojo.doc
at will. Note that while dojo.doc
is simply a reference to the
window.document
by default, it does
provide a uniform mechanism for identifying the context's current
document, which again can be quite useful for situations in which
managed object contexts are involved. dojo.body()
is a shortcut for obtaining the
body of a document.
Warning
The body
element is not
explicitly defined for a strict XHTML document and some other
documents you may encounter.
At a minimum, you should be aware of the following three functions from Base for manipulating context:
dojo.doc //Returns Document dojo.body( ) //Returns DomNode dojo.setContext(/*Object*/globalObject, /*Document*/globalDocument)
Finally, in the spirit of flexibility, Base also provides two
functions that allow you to evaluate a function in the context of
either a different dojo.global
environment or a different dojo.doc
than the one that currently exists:
dojo.withGlobal(/*Object*/globalObject, /*Function*/callback, /*Object*/thisObject, /*Array*/callbackArgs) dojo.withDoc(/*Object*/documentObject, /*Function*/callback, /*Object*/thisObject, /*Array*/callbackArgs)
It should be noted that using a Dojo function to operate
extensively in another document
or window
is not a well-tested usage of the
toolkit, so you may encounter support issues if going down that route.
Standard usage normally entails loading Dojo into every document where
you plan to use it. For lightweight operations, however, the context
functions discussed in this section should work fine.
Base's partial
function
allows you to partially apply parameters to a function as they
become available and perform final execution of the function at a
later time. Or, you might just need to apply all of the parameters
at once and then pass around a function reference that can be
executed—which is a little less messy than passing around the
function and the parameters all at the same time and a pattern that
is commonly used throughout the toolkit. Here's the API for partial
:
dojo.partial(*/Function|String*/func /*, arg1, ..., argN*/) //Returns Any
To illustrate, here's a simple example of partial
being used to partially apply
parameters to a function that adds a series of numbers:
function addThree(x,y,z) { console.log(x+y+z);} //apply two args now f = dojo.partial(addThree, 100,10); //apply the last one later f = dojo.partial(f, 1); //now evaluate f( ); //111
Base's hitch
function is
quite similar to partial in that it allows you partially apply
parameters to a function, but it also has the interesting twist that
it also allows you to permanently bind (or hitch) a function to a
specific execution context, regardless of whatever the final
execution context becomes. This can be especially handy for
situations in which you have callback functions and will never fully
know what the final execution context (and thus, this
) will be. Here's the API:
dojo.hitch(/*Object*/scope,
/*Function||String*/method /*, arg1, ... , argN*/)
//Returns Any
And to illustrate, here's a simple example that rewires an
Object
method:
var foo = { name : "Foo", greet : function( ) { console.log("Hi, I'm", this.name); } } var bar = { name : "Bar", greet : function( ) { console.log("Hi, I'm", this.name); } } foo.greet( ); //Hi, I'm Foo bar.greet( ); //Hi, I'm Bar /* Bind bar's greet method to another context */ bar.greet = dojo.hitch(foo, "greet"); / * Bar is now an impersonator */ bar.greet( ); // Hi, I'm Foo
To be clear, because the greet
function explicitly references a
context with this, the following code would not have successfully
rewired the greet
method:
bar.greet = foo.greet; bar.greet( );
Tip
You might find it interesting to know that with respect to
implementation, hitch
provides
the basis for partial
and
calling hitch
with null
as the scope is the functional
equivalent of calling partial
.
The section "Hitching Up Callbacks" in Chapter 4 provides an example of
using hitch
to manage the context
for data that is used within an asynchronous callback function—one
of its most common use cases because the callback function has a
different this
context than the
containing Object
.
Delegation is a programming pattern that entails one object relying on another object to perform an action, instead of implementing that action itself. Delegation is at the very heart of JavaScript as a prototype-based language because it is the pattern through which object properties are resolved in the prototype chain. Although delegation is at the very crux of JavaScript's inheritance implementation, which relies on the prototype chain being resolved at runtime, delegation as a pattern is very different from inheritance in true class-based programming languages like Java and C++, which often (but not always) resolve class hierarchies at compile time instead of runtime. In that regard, it is especially noteworthy that as a runtime feature, delegation necessarily relies on dynamic binding as a language feature.
Dojo's delegate
function
wraps up the details of dispatching delegation of an Object
's function through the following
API:
dojo.delegate(/*Object*/delegate, properties) //Returns Object
Building on the previous example, the following blurb
demonstrates how you might use delegation to get an Object
that dispatches responsibility for
a function to its delegate:
function Foo( ) { this.talk = function( ) {console.log("Hello, my name is", this.name);} } // Get a Function object back that has the name property // but dispatches, or delegates, responsiblity for the talk function // to the instance of Foo that is passed in. var bar = dojo.delegate(new Foo, {name : "Bar"}); // The talk method is resolved through the Foo delegate bar.talk( );
Chapter 10 is
devoted to the inheritance pattern facilitated by the toolkit's
dojo.declare
function, which can
be used to simulate class hierarchies with JavaScript; the chapter
also includes additional discussion on various approaches to
accomplishing inheritance patterns.
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.