mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-01-09 05:14:24 +00:00
711c087f8e
mozilla/js/rhino/org is now distributed between mozilla/js/rhino/src and mozilla/js/rhino/toolsrc. The build.xml has been split in three. Docs now live in the project directory. These changes mean that the cvs directories mirror the distribution and thus a distribution will build the same way as a cvs build.
175 lines
8.7 KiB
HTML
175 lines
8.7 KiB
HTML
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
|
<html>
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
<meta name="Author" content="Norris Boyd">
|
|
<meta name="GENERATOR" content="Mozilla/4.72 [en]C-NSCP (WinNT; U) [Netscape]">
|
|
<meta name="KeyWords" content="Rhino, JavaScript, Java">
|
|
<title>Scopes and Contexts</title>
|
|
</head>
|
|
<body bgcolor="#FFFFFF">
|
|
<script src="owner.js"></script>
|
|
|
|
<center>
|
|
<h1>
|
|
Scopes and Contexts</h1></center>
|
|
<script>document.write(owner());</script>
|
|
|
|
<br><script>
|
|
var d = new Date(document.lastModified);
|
|
document.write((d.getMonth()+1)+"/"+d.getDate()+"/"+d.getFullYear());
|
|
document.write('<br>');
|
|
</script>
|
|
|
|
<center>
|
|
<hr WIDTH="100%"></center>
|
|
|
|
<p>Before using Rhino in a concurrent environment, it is important to understand
|
|
the distinction between Contexts and scopes. Both are required to execute
|
|
scripts, but they play different roles. Simple embeddings of Rhino probably
|
|
won't need any of the information here, but more complicated embeddings
|
|
can gain performance and flexibility from the techniques described below.
|
|
<br>
|
|
<h2>
|
|
Contexts</h2>
|
|
The Rhino Context object is used to store thread-specific information about
|
|
the execution environment. There should be one and only one Context associated
|
|
with each thread that will be executing JavaScript.
|
|
<p>To associate the current thread with a Context, simply call the <tt>enter</tt>
|
|
method of Context:
|
|
<pre> Context cx = Context.enter();</pre>
|
|
Once you are done with execution, simply exit the Context:
|
|
<pre> Context.exit();</pre>
|
|
These calls will work properly even if there is already a Context associated
|
|
with the current thread. That context will be returned and an internal
|
|
counter incremented. Only when the counter reaches zero will it be disassociated
|
|
from the thread.
|
|
<p>Remember to put the <tt>exit()</tt> call in a <tt>finally</tt> block
|
|
if you're executing code that could throw an exception.
|
|
<br>
|
|
<h2>
|
|
Scopes</h2>
|
|
A scope is a set of JavaScript objects. Execution of scripts requires a
|
|
scope for top-level script variable storage as well as a place to find
|
|
standard objects like <tt>Function</tt> and <tt>Object</tt>.
|
|
<p>It's important to understand that a scope is independent of the Context
|
|
that created it. You can create a scope using one Context and then evaluate
|
|
a script using that scope and another Context (either by exiting the current
|
|
context and entering another, or by executing on a different thread). You
|
|
can even execute scripts on multiple threads simultaneously in the same
|
|
scope. Rhino guarantees that accesses to properties of JavaScript objects
|
|
are atomic across threads, but doesn't make any more guarantees for scripts
|
|
executing in the same scope at the same time. If two scripts use the same
|
|
scope simultaneously, the scripts are responsible for coordinating any
|
|
accesses to shared variables.
|
|
<p>A top-level scope is created by calling <tt>Context.initStandardObjects</tt>
|
|
to create all the standard objects:
|
|
<pre> Scriptable scope = cx.initStandardObjects(null);</pre>
|
|
The easiest way to embed Rhino is just to create a new scope this way whenever
|
|
you need one. However, <tt>initStandardObjects</tt> is an expensive method
|
|
to call and it allocates a fair amount of memory. We'll see below that
|
|
there are ways to share a scope created this way among multiple scopes
|
|
and threads.
|
|
<br>
|
|
<h2>
|
|
Name Lookup</h2>
|
|
So how are scopes used to look up names? In general, variables are looked
|
|
up by starting at the current variable object (which is different depending
|
|
on what code is being executed in the program), traversing its prototype
|
|
chain, and then traversing the parent chain. In the diagram below, the
|
|
order in which the six objects are traversed is indicated.
|
|
<center>
|
|
<p><img SRC="lookup.gif" height=194 width=500>
|
|
<br><i><font size=-1>Order of lookups in a two-deep scope chain with prototypes.</font></i></center>
|
|
|
|
<p>For a more concrete example, let's consider the following script:
|
|
<blockquote><tt>var g = 7;</tt>
|
|
<br><tt>function f(a) {</tt>
|
|
<br><tt> var v = 8;</tt>
|
|
<br><tt> x = v + a;</tt>
|
|
<br><tt>}</tt>
|
|
<br><tt>f(6);</tt></blockquote>
|
|
We have a top-level variable <tt>g</tt>, and the call to <tt>f</tt> will
|
|
create a new top-level variable <tt>x</tt>. All top-level variables are
|
|
properties of the scope object. When we start executing <tt>f</tt>, the
|
|
scope chain will start with the function's activation object and will end
|
|
with the top-level scope (see diagram below). The activation object has
|
|
two properties, 'a' for the argument, and 'v' for the variable. The top-level
|
|
scope has properties for the variable <tt>g</tt> and the function <tt>f</tt>.
|
|
<center>
|
|
<p><img SRC="scopes.gif" height=496 width=820>
|
|
<br><i><font size=-1>An example scope chain for a simple script.</font></i></center>
|
|
|
|
<p>When the statement <tt>x = v + a;</tt> is executed, the scope chain
|
|
is traversed looking for a 'x' property. When none is found, a new property
|
|
'x' is created in the top-level scope.
|
|
<h2>
|
|
Sharing Scopes</h2>
|
|
JavaScript is a language that uses delegation rather than traditional class-based
|
|
inheritance. This is a large topic in itself, but for our purposes it gives
|
|
us an easy way to share a set of read-only variables across multiple scopes.
|
|
To do this we set an object's prototype. When accessing a property of an
|
|
object in JavaScript, the object is first searched for a property with
|
|
the given name. If none is found, the object's prototype is searched. This
|
|
continues until either the object is found or the end of the prototype
|
|
chain is reached.
|
|
<p>So to share information across multiple scopes, we first create the
|
|
object we wish to share. Typically this object will have been created with
|
|
<tt>initStandardObjects</tt> and may also have additional objects specific
|
|
to the embedding. Then all we need to do is create a new object and call
|
|
its <tt>setPrototype</tt> method to set the prototype to the shared object:
|
|
<pre> Scriptable newScope = cx.newObject(sharedScope);
|
|
newScope.setPrototype(sharedScope);</pre>
|
|
The call to <tt>newObject</tt> simply creates a new JavaScript object with
|
|
no properties. It uses the <tt>sharedScope</tt> passed in to initialize
|
|
the prototype with the standard <tt>Object.prototype</tt> value.
|
|
<p>We can now use <tt>newScope</tt> as a scope for calls to evaluate scripts.
|
|
Let's call this scope the <i>instance scope</i>. Any top-level functions
|
|
or variables defined in the script will end up as properties of the instance
|
|
scope. Uses of standard objects like <tt>Function</tt>, <tt>String</tt>,
|
|
or <tt>RegExp</tt> will find the definitions in the shared scope. Multiple
|
|
instance scopes can be defined and have their own variables for scripts
|
|
yet share the definitions in the shared scope. These multiple instance
|
|
scopes can be used concurrently.
|
|
<br>
|
|
<h2>
|
|
Dynamic Scopes</h2>
|
|
There's one problem with the setup outlined above. Calls to functions in
|
|
JavaScript use <i>static scope</i>, which means that variables are first
|
|
looked up in the function and then, if not found there, in the lexically
|
|
enclosing scope. This causes problems if functions you define in your shared
|
|
scope need access to variables you define in your instance scope.
|
|
<p>With Rhino 1.5, it is possible to compile functions to use <i>dynamic
|
|
scope</i>. With dynamic scope, functions look at the top-level scope of
|
|
the calling function rather than their lexical scope. So we can store information
|
|
that varies across scopes in the instance scope yet still share functions
|
|
that manipulate that information reside in the shared scope.
|
|
<p>The <a href="http://lxr.mozilla.org/mozilla/source/js/rhino/examples/DynamicScopes.java">DynamicScopes
|
|
example</a> illustrates all the points discussed above.
|
|
<br>
|
|
<br>
|
|
<h2>
|
|
More on Scopes</h2>
|
|
The key things to determine in setting up scopes for your application are
|
|
<br>(1) What scope should global variables be created in when your script
|
|
executes an assignment to an undefined variable, and
|
|
<br>(2) What variables should your script have access to when it references
|
|
a variable?
|
|
<p>The answer to (1) determines which scope should be the ultimate parent
|
|
scope: Rhino follows the parent chain up to the top and places the variable
|
|
there. After you've constructed your parent scope chain, the answer to
|
|
question (2) may indicate that there are additional scopes that need to
|
|
be searched that are not in your parent scope chain. You can add these
|
|
as prototypes of scopes in your parent scope chain. When Rhino looks up
|
|
a variable, it starts in the current scope, walks the prototype chain,
|
|
then goes to the parent scope and its prototype chain, until there are
|
|
no more parent scopes left.
|
|
<br>
|
|
<h3>
|
|
|
|
<hr WIDTH="100%"><br>
|
|
<a href="index.html">back to top</a></h3>
|
|
|
|
</body>
|
|
</html>
|