зеркало из https://github.com/mozilla/gecko-dev.git
Fix doc bug.
This commit is contained in:
Родитель
f8a8f075f6
Коммит
0e0079e943
|
@ -1,174 +1,176 @@
|
|||
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
||||
<!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>
|
||||
|
||||
<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>
|
||||
<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.
|
||||
</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>
|
||||
</p>
|
||||
<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:
|
||||
method of Context: </p>
|
||||
<pre> Context cx = Context.enter();</pre>
|
||||
Once you are done with execution, simply exit the Context:
|
||||
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.
|
||||
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>
|
||||
</p>
|
||||
<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>
|
||||
<p>A top-level scope is created by calling <tt>Context.initStandardObjects</tt>
|
||||
to create all the standard objects:
|
||||
to create all the standard objects: </p>
|
||||
<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>
|
||||
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></p>
|
||||
</center>
|
||||
|
||||
<p>For a more concrete example, let's consider the following script: </p>
|
||||
<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></p>
|
||||
</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. </p>
|
||||
<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, and the parent of the new scope
|
||||
to null: </p>
|
||||
<pre> Scriptable newScope = cx.newObject(sharedScope);<br> newScope.setPrototype(sharedScope);<br> newScope.setParentScope(null);<br></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>
|
||||
</p>
|
||||
<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>
|
||||
<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>
|
||||
</p>
|
||||
<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>
|
||||
</p>
|
||||
<h3>
|
||||
<hr width="100%"><br>
|
||||
<a href="index.html">back to top</a>
|
||||
</h3>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
Загрузка…
Ссылка в новой задаче