Subversion Repositories FAQs

Compare Revisions

Last modification

Ignore whitespace Rev 44 → Rev 43

/trunk/cljs/faq_notes/closures.html
0,0 → 1,1574
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<title>Javascript Closures</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link href="../../faq.css" rel="stylesheet" type="text/css">
<link href="../notes.css" rel="stylesheet" type="text/css">
<style type="text/css">
CODE { white-space:nowrap; }
.scopeCh {
white-space:nowrap;
font-family:Courier, monospace;
}
</style>
</head>
<body>
 
<h1>Javascript Closures</h1>
<div id="faqNav">
<a href="../../">FAQ</a> &gt; <a href="../">FAQ Notes</a>
</div>
 
<ul>
<li><a href="#clIntro">Introduction</a></li>
<li><a href="#clResO">The Resolution of Property Names on Objects</a>
<ul>
<li><a href="#clResA">Assignment of Values</a></li>
<li><a href="#clResR">Reading of Values</a></li>
</ul>
</li>
<li><a href="#clIRExSc">Identifier Resolution, Execution Contexts and scope chains</a>
<ul>
<li><a href="#clExCon">The Execution Context</a></li>
<li><a href="#clScCh">scope chains and [[scope]]</a></li>
<li><a href="#clIdRes">Identifier Resolution</a></li>
</ul>
</li>
<li><a href="#clClose">Closures</a>
<ul>
<li><a href="#clAtGb">Automatic Garbage Collection</a></li>
<li><a href="#clFrmC">Forming Closures</a></li>
</ul>
</li>
<li><a href="#clClDo">What can be done with Closures?</a>
<ul>
<li><a href="#clSto">Example 1: setTimeout with Function References</a></li>
<li><a href="#clObjI">Example 2: Associating Functions with Object Instance Methods</a></li>
<li><a href="#clEncap">Example 3: Encapsulating Related Functionality</a></li>
<li><a href="#clOtE">Other Examples</a></li>
</ul>
</li>
<li><a href="#clAc">Accidental Closures</a></li>
<li><a href="#clMem">The Internet Explorer Memory Leak Problem</a></li>
</ul>
 
<h2 id="clIntro">Introduction</h2>
 
<blockquote cite="http://groups.google.com/groups?selm=wu535hos.fsf@hotpop.com">
<dl>
<dt id="clDefN">Closure</dt>
<dd>A &quot;closure&quot; is an expression (typically a function) that
can have free variables together with an environment that binds
those variables (that &quot;closes&quot; the expression).
<dd>
</dl>
</blockquote>
 
<p>
Closures are one of the most powerful features of ECMAScript
(javascript) but they cannot be property exploited without
understanding them. They are, however, relatively easy to create,
even accidentally, and their creation has potentially harmful
consequences, particularly in some relatively common web browser
environments. To avoid accidentally encountering the drawbacks and
to take advantage of the benefits they offer it is necessary to
understand their mechanism. This depends heavily on the role of
scope chains in identifier resolution and so on the resolution of
property names on objects.
</p>
 
<p>
The simple explanation of a Closure is that ECMAScript allows inner
functions; function definitions and function expressions that are
inside the function bodes of other functions. And that those inner
functions are allowed access to all of the local variables, parameters
and declared inner functions within their outer function(s). A closure
is formed when one of those inner functions is made accessible outside
of the function in which it was contained, so that it may be executed
after the outer function has returned. At which point it still has
access to the local variables, parameters and inner function
declarations of its outer function. Those local variables, parameter
and function declarations (initially) have the values that they had
when the outer function returned and may be interacted with by the
inner function.
</p>
 
<p>
Unfortunately, properly understanding closures requires an
understanding of the mechanism behind them, and quite a bit of
technical detail. While some of the ECMA 262 specified algorithms have
been brushed over in the early part of the following explanation, much
cannot be omitted or easily simplified. Individuals familiar with
object property name resolution may skip that section but only people
already familiar with closures can afford to skip the following
sections, and they can stop reading now and get back to exploiting
them.
</p>
 
<h2 id="clResO">The Resolution of Property Names on Objects</h2>
 
<p>
ECMAScript recognises two categories of object, &quot;Native Object&quot;
and &quot;Host Object&quot; with a sub-category of native objects called
&quot;Built-in Object&quot; (ECMA 262 3rd Ed Section 4.3). Native objects
belong to the language and host objects are provided by the environment,
and may be, for example, document objects, DOM nodes and the like.
</p>
 
<p>
Native objects are loose and dynamic bags of named properties (some
implementations are not that dynamic when it comes to the built in
object sub-category, though usually that doesn't matter). The defined
named properties of an object will hold a value, which may be a
reference to another Object (functions are also Objects in this sense)
or a primitive value: String, Number, Boolean, Null or Undefined. The
Undefined primitive type is a bit odd in that it is possible to assign
a value of Undefined to a property of an object but doing so does not
remove that property from the object; it remains a defined named
property, it just holds the value <code>undefined</code>.
</p>
 
<p>
The following is a simplified description of how property values are
read and set on objects with the internal details brushed over to the
greatest extent possible.
</p>
 
<h3><a name="clResA" id="clResA">Assignment of Values</a></h3>
 
<p>
Named properties of objects can be created, or values set on existing
named properties, by assigning a value to that named property. So
given:-
</p>
 
<pre>
var objectRef = new Object(); <span class="commentJS">//create a generic javascript object.</span>
</pre>
 
<p>
A property with the name &quot;testNumber&quot; can be created as:-
</p>
 
<pre>
objectRef.testNumber = 5;
<span class="commentJS">/* - or:- */</span>
objectRef[&quot;testNumber&quot;] = 5;
</pre>
 
<p>
The object had no &quot;testNumber&quot; property prior to the
assignment but one is created when the assignment is made. Any
subsequent assignment does not need to create the property, it just
re-sets its value:-
</p>
 
<pre>
objectRef.testNumber = 8;
<span class="commentJS">/* - or:- */</span>
objectRef[&quot;testNumber&quot;] = 8;
</pre>
 
<p>
Javascript objects have prototypes that can themselves be objects, as
will be described shortly, and that prototype may have named
properties. But this has no role in assignment. If a value is assigned
and the actual object does not have a property with the corresponding
name a property of that name is created and the value is assigned to
it. If it has the property then its value is re-set.
</p>
 
<h3><a name="clResR" id="clResR">Reading of Values</a></h3>
 
<p>
It is in reading values from object properties that prototypes come
into play. If an object has a property with the property name used in
the property accessor then the value of that property is returned:-
</p>
 
<pre>
<span class="commentJS">/* Assign a value to a named property. If the object does not have a
property with the corresponding name prior to the assignment it
will have one after it:-
*/</span>
objectRef.testNumber = 8;
 
<span class="commentJS">/* Read the value back from the property:- */</span>
 
var val = objectRef.testNumber;
<span class="commentJS">/* and - val - now holds the value 8 that was just assigned to the
named property of the object. */</span>
</pre>
 
<p>
But all objects may have prototypes, and prototypes are objects so they, in
turn, may have prototypes, which may have prototypes, and so on forming
what is called the prototype chain. The prototype chain ends when one
of the objects in the chain has a null prototype. The default prototype for the
<code>Object</code> constructor has a null prototype so:-
</p>
 
<pre>
var objectRef = new Object(); <span class="commentJS">//create a generic javascript object.</span>
</pre>
 
<p>
Creates an object with the prototype <code>Object.prototype</code> that itself has a
null prototype. So the prototype chain for <code>objectRef</code> contains only one
object: <code>Object.prototype</code>. However:-
</p>
 
<pre>
<span class="commentJS">/* A &quot;constructor&quot; function for creating objects of a -
MyObject1 - type.
*/</span>
function MyObject1(formalParameter){
<span class="commentJS">/* Give the constructed object a property called - testNumber - and
assign it the value passed to the constructor as its first
argument:-
*/</span>
this.testNumber = formalParameter;
}
 
<span class="commentJS">/* A &quot;constructor&quot; function for creating objects of a -
MyObject2 - type:-
*/</span>
function MyObject2(formalParameter){
<span class="commentJS">/* Give the constructed object a property called - testString -
and assign it the value passed to the constructor as its first
argument:-
*/</span>
this.testString = formalParameter;
}
 
<span class="commentJS">/* The next operation replaces the default prototype associated with
all MyObject2 instances with an instance of MyObject1, passing the
argument - 8 - to the MyObject1 constructor so that its -
testNumber - property will be set to that value:-
*/</span>
MyObject2.prototype = new MyObject1( 8 );
 
<span class="commentJS">/* Finally, create an instance of - MyObject2 - and assign a reference
to that object to the variable - objectRef - passing a string as the
first argument for the constructor:-
*/</span>
 
var objectRef = new MyObject2( &quot;String_Value&quot; );
</pre>
 
<p>
The instance of <code>MyObject2</code> referred to by the <code>objectRef</code> variable has a
prototype chain. The first object in that chain is the instance of
<code>MyObject1</code> that was created and assigned to the prototype
property of the <code>MyObject2</code> constructor. The instance of
<code>MyObject1</code> has a prototype, the object that was assigned to the function
<code>MyObject1</code>'s prototype property by the implementation. That object has
a prototype, the default <code>Object</code> prototype that corresponds with the
object referred to by <code>Object.prototype</code>. <code>Object.prototype</code> has a null
prototype so the prototype chain comes to an end at this point.
</p>
<p>
When a property accessor attempts to read a named property form the
object referred to by the variable <code>objectRef</code> the whole
prototype chain can enter into the process. In the simple case:-
</p>
 
<pre>
var val = objectRef.testString;
</pre>
 
<p>
- the instance of <code>MyObject2</code> referred to by <code>objectRef</code> has
a property with the name &quot;testString&quot; so it is the value of
that property, set to &quot;String_Value&quot;, that is assigned to the
variable <code>val</code>. However:-
</p>
 
<pre>
var val = objectRef.testNumber;
</pre>
 
<p>
- cannot read a named property form the instance of
<code>MyObject2</code> itself as it has no such property but the
variable <code>val</code> is set to the value of <code>8</code> rather
than undefined because having failed to find a corresponding named
property on the object itself the interpreter then examines the object
that is its prototype. Its prototype is the instance of
<code>MyObject1</code> and it was created with a property named
&quot;testNumber&quot; with the value <code>8</code> assigned to that property, so
the property accessor evaluates as the value <code>8</code>. Neither
<code>MyObject1</code> or <code>MyObject2</code> have defined a
<code>toString</code> method, but if a property accessor attempts to
read the value of a <code>toString</code> property from
<code>objectRef</code>:-
</p>
 
<pre>
var val = objectRef.toString;
</pre>
 
<p>
- the <code>val</code> variable is assigned a reference to a function.
That function is the <code>toString</code> property of
<code>Object.prototype</code> and is returned because the process of
examining the prototype of <code>objectRef</code>, when
<code>objectRef</code> turns out not to have a &quot;toString&quot;
property, is acting on an object, so when that prototype is found to
lack the property its prototype is examined in turn. Its prototype
is <code>Object.prototype</code>, which does have a
<code>toString</code> method so it is a reference to that function
object that is returned.
</p>
 
<p>
Finally:-
</p>
 
<pre>
var val = objectRef.madeUpProperty;
</pre>
 
<p>
- returns <code>undefined</code>, because as the process of working up the prototype
chain finds no properties on any of the object with the name
&quot;madeUpPeoperty&quot; it eventually gets to the prototype of
<code>Object.prototype</code>, which is null, and the process ends
returning <code>undefined</code>.
</p>
 
<p>
The reading of named properties returns the first value found, on the
object or then from its prototype chain. The assigning of a value to a
named property on an object will create a property on the object itself
if no corresponding property already exists.
</p>
 
<p>
This means that if a value was assigned as
<code>objectRef.testNumber = 3</code> a &quot;testNumber&quot; property
will be created on the instance of <code>MyObject2</code> itself, and
any subsequent attempts to read that value will retrieve that value as
set on the object. The prototype chain no longer needs to be examined
to resolve the property accessor, but the instance of
<code>MyObject1</code> with the value of <code>8</code> assigned to its
&quot;testNumber&quot; property is unaltered. The assignment to the
<code>objectRef</code> object masks the corresponding property in its
prototype chain.
</p>
 
<p>
Note: ECMAScript defines an internal <code>[[prototype]]</code>
property of the internal Object type. This property is not directly accessible with
scripts, but it is the chain of objects referred to with the
internal <code>[[prototype]]</code> property that is used in property
accessor resolution; the object's prototype chain. A public
<code>prototype</code> property exists to allow the assignment,
definition and manipulation of prototypes in association with the
internal <code>[[prototype]]</code> property. The details of the
relationship between to two are described in ECMA 262 (3rd edition)
and are beyond the <dfn>scope</dfn> of this discussion.
</p>
 
<h2 id="clIRExSc">Identifier Resolution, Execution Contexts and scope chains</h2>
 
<h3 id="clExCon">The Execution Context</h3>
 
<p>
An <dfn>execution context</dfn> is an abstract concept used by the ECMSScript
specification (ECMA 262 3rd edition) to define the behaviour required
of ECMAScript implementations. The specification does not say anything
about how <dfn>execution contexts</dfn> should be implemented but execution
contexts have associated attributes that refer to specification defined
structures so they might be conceived (and even implemented) as objects
with properties, though not public properties.
</p>
 
<p>
All javascript code is executed in an <dfn>execution context</dfn>. Global code
(code executed inline, normally as a JS file, or <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> page, loads) gets
executed in <dfn>global</dfn> <dfn>execution context</dfn>, and each invocation of a function (possibly as a constructor) has an associated
<dfn>execution context</dfn>. Code executed with the <code>eval</code> function
also gets a distinct execution context but as <code>eval</code> is
never normally used by javascript programmers it will not be discussed
here. The specified details of <dfn>execution contexts</dfn> are to be found in
section 10.2 of ECMA 262 (3rd edition).
</p>
 
<p>
When a javascript function is called it enters an <dfn>execution context</dfn>,
if another function is called (or the same function recursively) a new
<dfn>execution context</dfn> is created and execution enters that context for the
duration of the function call. Returning to the original execution
context when that called function returns. Thus running javascript code
forms a stack of <dfn>execution contexts</dfn>.
</p>
 
<p>
When an <dfn>execution context</dfn> is created a number of things happen in a
defined order. First, in the <dfn>execution context</dfn> of a function, an
&quot;Activation&quot; object is created. The activation object is
another specification mechanism. It can be considered as an object
because it ends up having accessible named properties, but it is not a
normal object as it has no prototype (at least not a defined prototype)
and it cannot be directly referenced by javascript code.
</p>
 
<p>
The next step in the creation of the <dfn>execution context</dfn> for a function
call is the creation of an <code>arguments</code> object, which is an
array-like object with integer indexed members corresponding with the
arguments passed to the function call, in order. It also has
<code>length</code> and <code>callee</code> properties (which are not
relevant to this discussion, see the spec for details). A property of
the Activation object is created with the name &quot;arguments&quot;
and a reference to the <code>arguments</code> object is assigned to
that property.
</p>
 
<p>
Next the <dfn>execution context</dfn> is assigned a <dfn>scope</dfn>. A <dfn>scope</dfn> consists of a
list (or chain) of objects. Each function object has an internal
<code>[[scope]]</code> property (which we will go into more detail
about shortly) that also consists of a list (or chain) of objects.
The <dfn>scope</dfn> that is assigned to the <dfn>execution context</dfn> of a function call
consists of the list referred to by the <code>[[scope]]</code> property
of the corresponding function object with the Activation object added
at the front of the chain (or the top of the list).
</p>
 
<p>
Then the process of &quot;variable instantiation&quot; takes place using an object
that ECMA 262 refers to as the &quot;Variable&quot; object. However,
the Activation object is used as the Variable object (note this, it is
important: they are the same object). Named properties of the Variable
object are created for each of the function's formal parameters, and if
arguments to the function call correspond with those parameters the
values of those arguments are assigned to the properties (otherwise the
assigned value is <code>undefined</code>). Inner function definitions
are used to create function objects which are assigned to properties of
the Variable object with names that correspond to the function name
used in the function declaration. The last stage of variable
instantiation is to create named properties of the Variable object
that correspond with all the local variables declared within the
function.
</p>
 
<p>
The properties created on the Variable object that correspond with
declared local variables are initially assigned <code>undefined</code>
values during variable instantiation, the actual initialisation of
local variables does not happen until the evaluation of the
corresponding assignment expressions during the execution of the
function body code.
</p>
 
<p>
It is the fact that the Activation object, with its
<code>arguments</code> property, and the Variable object, with named
properties corresponding with function local variables, are the same
object, that allows the identifier <code>arguments</code> to be treated
as if it was a function local variable.
</p>
 
<p>
Finally a value is assigned for use with the <code>this</code> keyword.
If the value assigned refers to an object then property accessors
prefixed with the <code>this</code> keyword reference properties of
that object. If the value assigned (internally) is null then the
<code>this</code> keyword will refer to the global object.
</p>
 
<p>
The global execution context gets some slightly different handling as
it does not have arguments so it does not need a defined Activation
object to refer to them. The global execution context does need a <dfn>scope</dfn>
and its <dfn>scope chain</dfn> consists of exactly one object, the global object.
The global execution context does go through variable instantiation,
its inner functions are the normal top level function declarations that
make up the bulk of javascript code. The global object is used as the
Variable object, which is why globally declared functions become
properties of the global object. As do globally declared variables.
</p>
 
<p>
The global execution context also uses a reference to the global object
for the <code>this</code> object.
</p>
 
<h3 id="clScCh">scope chains and [[scope]]</h3>
 
<p>
The <dfn>scope chain</dfn> of the execution context for a function call is
constructed by adding the execution context's Activation/Variable
object to the front of the <dfn>scope chain</dfn> held in the function
object's <code>[[scope]]</code> property, so it is important to
understand how the internal <code>[[scope]]</code> property is
defined.
</p>
 
<p>
In ECMAScript functions are objects, they are created during variable
instantiation from function declarations, during the evaluation of
function expressions or by invoking the <code>Function</code>
constructor.
</p>
 
<p>
Function objects created with the <code>Function</code> constructor
always have a <code>[[scope]]</code> property referring to a <dfn>scope
chain</dfn> that only contains the global object.
</p>
 
<p>
Function objects created with function declarations or function
expressions have the <dfn>scope chain</dfn> of the execution context in which
they are created assigned to their internal <code>[[scope]]</code>
property.
</p>
 
<p>
In the simplest case of a global function declaration such as:-
</p>
 
<pre>
function exampleFunction(formalParameter){
... <span class="commentJS">// function body code</span>
}
</pre>
 
<p>
- the corresponding function object is created during the variable
instantiation for the global execution context. The global execution
context has a <dfn>scope chain</dfn> consisting of only the global object. Thus
the function object that is created and referred to by the property of
the global object with the name &quot;exampleFunction&quot; is
assigned an internal <code>[[scope]]</code> property referring to a
<dfn>scope chain</dfn> containing only the global object.
</p>
 
<p>
A similar <dfn>scope chain</dfn> is assigned when a function expression is
executed in the global context:-
</p>
 
<pre>
var exampleFuncRef = function(){
... <span class="commentJS">// function body code</span>
}
</pre>
 
<p>
- except in this case a named property of the global object is created
during variable instantiation for the global execution context but the
function object is not created, and a reference to it assigned to the
named property of the global object, until the assignment expression is
evaluated. But the creation of the function object still happens in the
global execution context so the <code>[[scope]]</code> property of the
created function object still only contains the global object in the
assigned scope chain.
</p>
 
<p>
Inner function declarations and expressions result in function objects
being created within the execution context of a function so they get
more elaborate scope chains. Consider the following code, which defines
a function with an inner function declaration and then executes the
outer function:-
</p>
 
<pre>
function exampleOuterFunction(formalParameter){
function exampleInnerFuncitonDec(){
... <span class="commentJS">// inner function body</span>
}
... <span class="commentJS">// the rest of the outer function body.</span>
}
 
exampleOuterFunction( 5 );
</pre>
 
<p>
The function object corresponding with the outer function declaration
is created during variable instantiation in the global execution context
so its <code>[[scope]]</code> property contains the one item scope
chain with only the global object in it.
</p>
 
<p>
When the global code executes the call to the
<code>exampleOuterFunction</code> a new execution context is created for
that function call and an Activation/Variable object along with it.
The <dfn>scope</dfn> of that new execution context becomes the chain consisting of
the new Activation object followed by the chain refereed to by the
outer function object's <code>[[scope]]</code> property (just the
global object). Variable instantiation for that new execution context
results in the creation of a function object that corresponds with the
inner function definition and the <code>[[scope]]</code> property of
that function object is assigned the value of the <dfn>scope</dfn> from the
execution context in which it was created. A <dfn>scope chain</dfn> that contains
the Activation object followed by the global object.
</p>
 
<p>
So far this is all automatic and controlled by the structure and
execution of the source code. The <dfn>scope chain</dfn> of the execution context
defines the <code>[[scope]]</code> properties of the function objects
created and the <code>[[scope]]</code> properties of the function
objects define the <dfn>scope</dfn> for their execution contexts (along with the
corresponding Activation object). But ECMAScript provides the
<code>with</code> statement as a means of modifying the scope chain.
</p>
 
<p>
The <code>with</code> statement evaluates an expression and if that
expression is an object it is added to the <dfn>scope chain</dfn> of the current
execution context (in front of the Activation/Variable object). The
<code>with</code> statement then executes another statement (that may
itself be a block statement) and then restores the execution context's
<dfn>scope chain</dfn>to what it was before.
</p>
 
<p>
A function declaration could not be affected by a <code>with</code>
statement as they result in the creation of function objects during
variable instantiation, but a function expression can be evaluated
inside a <code>with</code> statement:-
</p>
 
<pre>
<span class="commentJS">/* create a global variable - y - that refers to an object:- */</span>
var y = {x:5}; <span class="commentJS">// object literal with an - x - property</span>
function exampleFuncWith(){
var z;
<span class="commentJS">/* Add the object referred to by the global variable - y - to the
front of he scope chain:-
*/</span>
with(y){
<span class="commentJS">/* evaluate a function expression to create a function object
and assign a reference to that function object to the local
variable - z - :-
*/</span>
z = function(){
... <span class="commentJS">// inner function expression body;</span>
}
}
...
}
 
<span class="commentJS">/* execute the - exampleFuncWith - function:- */</span>
exampleFuncWith();
</pre>
 
<p>
When the <code>exampleFuncWith</code> function is called the resulting
execution context has a <dfn>scope chain</dfn> consisting of its Activation object
followed by the global object. The execution of the <code>with</code>
statement adds the object referred to by the global variable
<code>y</code> to the front of that <dfn>scope chain</dfn> during the evaluation
of the function expression. The function object created by the
evaluation of the function expression is assigned a
<code>[[scope]]</code> property that corresponds with the <dfn>scope</dfn> of the
execution context in which it is created. A <dfn>scope chain</dfn> consisting of
object <code>y</code> followed by the Activation object from the
execution context of the outer function call, followed by the global
object.
</p>
 
<p>
When the block statement associated with the <code>with</code>
statement terminates the <dfn>scope</dfn> of the execution context is restored
(the <code>y</code> object is removed), but the function object has
been created at that point and its <code>[[scope]]</code> property
assigned a reference to a <dfn>scope chain</dfn> with the <code>y</code> object
at its head.
</p>
 
<h3><a name="clIdRes" id="clIdRes">Identifier Resolution</a></h3>
 
<p>
Identifiers are resolved against the scope chain. ECMA 262 categorises
<code>this</code> as a keyword rather than an identifier, which is not
unreasonable as it is always resolved dependent on the
<code>this</code> value in the execution context in which it is used,
without reference to the scope chain.
</p>
 
<p>
Identifier resolution starts with the first object in the scope chain.
It is checked to see if it has a property with a name that corresponds
with the identifier. Because the <dfn>scope chain</dfn> is a chain of objects
this checking encompasses the prototype chain of that object (if it
has one). If no corresponding value can be found on the first object
in the <dfn>scope chain</dfn> the search progresses to the next object. And so on until
one of the objects in the chain (or one of its prototypes) has a
property with a name that corresponds with the identifier or the scope
chain is exhausted.
</p>
 
<p>
The operation on the identifier happens in the same way as the use of
property accessors on objects described above. The object identified
in the <dfn>scope chain</dfn> as having the corresponding property takes the
place of the object in the property accessor and the identifier acts
as a property name for that object. The global object is always at the
end of the scope chain.
</p>
 
<p>
As execution contexts associated with function calls will have the
Activation/Variable object at the front of the chain, identifiers used
in function bodies are effectively first checked to see whether they
correspond with formal parameters, inner function declaration names or
local variables. Those would be resolved as named properties of the
Activation/Variable object.
</p>
 
<h2><a name="clClose" id="clClose">Closures</a></h2>
 
<h3><a name="clAtGb" id="clAtGb">Automatic Garbage Collection</a></h3>
 
<p>
ECMAScript uses automatic garbage collection. The specification
does not define the details, leaving that to the implementers to sort
out, and some implementations are known to give a very low priority to
their garbage collection operations. But the general idea is that if an
object becomes un-referable (by having no remaining references to it
left accessible to executing code) it becomes available for garbage
collection and will at some future point be destroyed and any resources
it is consuming freed and returned to the system for re-use.
</p>
 
<p>
This would normally be the case upon exiting an execution context. The
<dfn>scope chain</dfn> structure, the Activation/Variable object and any objects
created within the execution context, including function objects, would
no longer be accessible and so would become available for garbage
collection.
</p>
 
<h3><a name="clFrmC" id="clFrmC">Forming Closures</a></h3>
 
<p>
A closure is formed by returning a function object that was created
within an execution context of a function call from that function call
and assigning a reference to that inner function to a property of another
object. Or by directly assigning a reference to such a function object
to, for example, a global variable, a property of a globally accessible
object or an object passed by reference as an argument to the outer
function call. e.g:-
</p>
 
<pre>
function exampleClosureForm(arg1, arg2){
var localVar = 8;
function exampleReturned(innerArg){
return ((arg1 + arg2)/(innerArg + localVar));
}
<span class="commentJS">/* return a reference to the inner function defined as -
exampleReturned -:-
*/</span>
return exampleReturned;
}
 
var globalVar = exampleClosureForm(2, 4);
</pre>
 
<p>
Now the function object created within the execution context of the
call to <code>exampleClosureForm</code> cannot be garbage collected
because it is referred to by a global variable and is still accessible,
it can even be executed with <code>globalVar(n)</code>.
</p>
 
<p>
But something a little more complicated has happened because the
function object now referred to by <code>globalVar</code> was created
with a <code>[[scope]]</code> property referring to a scope chain
containing the Activation/Variable object belonging to the execution
context in which it was created (and the global object). Now the
Activation/Variable object cannot be garbage collected either as the
execution of the function object referred to by <code>globalVar</code>
will need to add the whole <dfn>scope chain</dfn> from its <code>[[scope]]</code>
property to the <dfn>scope</dfn> of the execution context created for each call to
it.
</p>
 
<p>
A closure is formed. The inner function object has the free variables
and the Activation/Variable object on the function's <dfn>scope chain</dfn> is
the environment that binds them.
</p>
 
<p>
The Activation/Variable object is trapped by being
referred to in the <dfn>scope chain</dfn> assigned to the internal
<code>[[scope]]</code> property of the function object now referred to
by the <code>globalVar</code> variable. The Activation/Variable object
is preserved along with its state; the values of its properties. Scope
resolution in the execution context of calls to the inner function will
resolve identifiers that correspond with named properties of that
Activation/Variable object as properties of that object. The value of
those properties can still be read and set even though the execution
context for which it was created has exited.
</p>
 
<p>
In the example above that Activation/Variable object has a state that
represents the values of formal parameters, inner function definitions
and local variables, at the time when the outer function returned
(exited its execution context). The <code>arg1</code> property has the
value <code>2</code>,the <code>arg2</code> property the value
<code>4</code>, <code>localVar</code> the value <code>8</code> and an
<code>exampleReturned</code> property that is a reference to the inner
function object that was returned form the outer function. (We will be
referring to this Activation/Variable object as "ActOuter1" in later
discussion, for convenience.)
</p>
 
<p>
If the <code>exampleClosureForm</code> function was called again as:-
</p>
 
<pre>
var secondGlobalVar = exampleClosureForm(12, 3);
</pre>
 
<p>
- a new execution context would be created, along with a new Activation
object. And a new function object would be returned, with its own
distinct <code>[[scope]]</code> property referring to a scope chain
containing the Activation object form this second execution context,
with <code>arg1</code> being <code>12</code> and <code>arg2</code>
being <code>3</code>. (We will be referring to this Activation/Variable
object as &quot;ActOuter2&quot; in later discussion, for convenience.)
</p>
 
<p>
A second and distinct closure has been formed by the second execution
of <code>exampleClosureForm</code>.
</p>
 
<p>
The two function objects created by the execution of
<code>exampleClosureForm</code> to which references have been assigned
to the global variable <code>globalVar</code> and
<code>secondGlobalVar</code> respectively, return the expression
<code>((arg1 + arg2)/(innerArg + localVar))</code>. Which applies
various operators to four identifiers. How these identifiers are
resolved is critical to the use and value of closures.
</p>
 
<p>
Consider the execution of the function object referred to by
<code>globalVar</code>, as <code>globalVar(2)</code>. A new execution
context is created and an Activation object (we will call it
&quot;ActInner1&quot;), which is added to the head of the scope chain
referred to the <code>[[scope]]</code> property of the executed
function object. ActInner1 is given a property named
<code>innerArg</code>, after its formal parameter and the argument
value <code>2</code> assigned to it. The <dfn>scope chain</dfn> for this new
execution context is: <span class="scopeCh">ActInner1-&gt;</span>
<span class="scopeCh">ActOuter1-&gt;</span>
<span class="scopeCh">global object</span>.
</p>
 
<p>
Identifier resolution is done against the <dfn>scope chain</dfn> so in order
to return the value of the expression
<code>((arg1 + arg2)/(innerArg + localVar))</code> the values of the
identifiers will be determined by looking for properties, with names
corresponding with the identifiers, on each object in the scope chain
in turn.
</p>
 
<p>
The first object in the chain is ActInner1 and it has a property named
<code>innerArg</code> with the value <code>2</code>. All of the other
3 identifiers correspond with named properties of ActOuter1;
<code>arg1</code> is <code>2</code>, <code>arg2</code> is
<code>4</code> and <code>localVar</code> is <code>8</code>. The
function call returns <code>((2 + 4)/(2 + 8))</code>.
</p>
 
<p>
Compare that with the execution of the otherwise identical function
object referred to by <code>secondGlobalVar</code>, as
<code>secondGlobalVar(5)</code>. Calling the Activation object for
this new execution context &quot;ActInner2&quot;, the scope chain
becomes: <span class="scopeCh">ActInner2-&gt;</span>
<span class="scopeCh">ActOuter2-&gt;</span>
<span class="scopeCh">global object</span>. ActInner2 returns
<code>innerArg</code> as <code>5</code> and ActOuter2 returns
<code>arg1</code>, <code>arg2</code> and <code>localVar</code> as
<code>12</code>, <code>3</code> and <code>8</code> respectively. The
value returned is <code>((12 + 3)/(5 + 8))</code>.
</p>
 
<p>
Execute <code>secondGlobalVar</code> again and a new Activation object
will appear at the front of the <dfn>scope chain</dfn> but ActOuter2 will still
be next object in the chain and the value of its named properties will
again be used in the resolution of the identifiers <code>arg1</code>,
<code>arg2</code> and <code>localVar</code>.
</p>
 
<p>
This is how ECMAScript inner functions gain, and maintain, access to the formal
parameters, declared inner functions and local variables of the
execution context in which they were created. And it is how the
forming of a closure allows such a function object to keep referring
to those values, reading and writing to them, for as long as it
continues to exist. The Activation/Variable object from the execution
context in which the inner function was created remains on the scope
chain referred to by the function object's <code>[[scope]]</code>
property, until all references to the inner function are freed and
the function object is made available for garbage collection (along
with any now unneeded objects on its scope chain).
</p>
 
<p>
Inner function may themselves have inner functions, and the inner
functions returned from the execution of functions to form closures
may themselves return inner functions and form closures of their own.
With each nesting the <dfn>scope chain</dfn> gains extra Activation objects
originating with the execution contexts in which the inner function
objects were created. The ECMAScript specification requires a scope
chain to be finite, but imposes no limits on their length.
Implementations probably do impose some practical limitation but no
specific magnitude has yet been reported. The potential for nesting
inner functions seems so far to have exceeded anyone's desire to
code them.
</p>
 
<h2><a name="clClDo" id="clClDo">What can be done with Closures?</a></h2>
 
<p>
Strangely the answer to that appears to be anything and everything.
I am told that closures enable ECMAScript to emulate anything, so the
limitation is the ability to conceive and implement the emulation. That
is a bit esoteric and it is probably better to start with something a
little more practical.
</p>
 
 
<h3><a name="clSto" id="clSto">Example 1: setTimeout with Function References</a></h3>
 
 
<p>
A common use for a closure is to provide parameters for the execution
of a function prior to the execution of that function. For example,
when a function is to be provided as the first argument to the
<code>setTimout</code> function that is common in web browser
environments.
</p>
 
<p>
<code>setTimeout</code> schedules the execution of a function (or a
string of javascript source code, but not in this context), provided as
its first argument, after an interval expressed in milliseconds (as its
second argument). If a piece of code wants to use
<code>setTimeout</code> it calls the <code>setTimeout</code> function
and passes a reference to a function object as the first argument and
the millisecond interval as the second, but a reference to a function
object cannot provide parameters for the scheduled execution of that
function.
</p>
 
<p>
However, code could call another function that returned a reference to
an inner function object, with that inner function object being passed
by reference to the <code>setTimeout</code> function. The parameters to
be used for the execution of the inner function are passed with the
call to the function that returns it. <code>setTimout</code> executes
the inner function without passing arguments but that inner function
can still access the parameters provided by the call to the outer
function that returned it:-
</p>
 
<pre>
function callLater(paramA, paramB, paramC){
<span class="commentJS">/* Return a reference to an anonymous inner function created
with a function expression:-
*/</span>
return (function(){
<span class="commentJS">/* This inner function is to be executed with - setTimeout
- and when it is executed it can read, and act upon, the
parameters passed to the outer function:-
*/</span>
paramA[paramB] = paramC;
});
}
 
...
 
<span class="commentJS">/* Call the function that will return a reference to the inner function
object created in its execution context. Passing the parameters that
the inner function will use when it is eventually executed as
arguments to the outer function. The returned reference to the inner
function object is assigned to a local variable:-
*/</span>
var functRef = callLater(elStyle, "display", "none");
<span class="commentJS">/* Call the setTimeout function, passing the reference to the inner
function assigned to the - functRef - variable as the first argument:-
*/</span>
hideMenu=setTimeout(functRef, 500);
</pre>
 
<h3><a name="clObjI" id="clObjI">Example 2: Associating Functions with Object Instance Methods</a></h3>
 
<p>
There are many other circumstances when a reference to a function
object is assigned so that it would be executed at some future time
where it is useful to provide parameters for the execution of that
function that would not be easily available at the time of execution
but cannot be known until the moment of assignment.
</p>
 
<p>
One example might be a javascript object that is designed to
encapsulate the interactions with a particular DOM element. It has
<code>doOnClick</code>, <code>doMouseOver</code> and
<code>doMouseOut</code> methods and wants to execute those methods
when the corresponding events are triggered on the DOM element, but
there may be any number of instances of the javascript object created
associated with different DOM elements and the individual object
instances do not know how they will be employed by the code that
instantiated them. The object instances do not know how to reference
themselves globally because they do not know which global variables
(if any) will be assigned references to their instances.
</p>
 
<p>
So the problem is to execute an event handling function that has an
association with a particular instance of the javascript object, and
knows which method of that object to call.
</p>
 
<p>
The following example uses a small generalised closure based function
that associates object instances with element event handlers.
Arranging that the execution of the event handler calls the specified
method of the object instance, passing the event object and a reference
to the associated element on to the object method and returning the
method's return value.
</p>
 
<pre>
<span class="commentJS">/* A general function that associates an object instance with an event
handler. The returned inner function is used as the event handler.
The object instance is passed as the - obj - parameter and the name
of the method that is to be called on that object is passed as the -
methodName - (string) parameter.
*/</span>
function associateObjWithEvent(obj, methodName){
<span class="commentJS">/* The returned inner function is intended to act as an event
handler for a DOM element:-
*/</span>
return (function(e){
<span class="commentJS">/* The event object that will have been parsed as the - e -
parameter on DOM standard browsers is normalised to the IE
event object if it has not been passed as an argument to the
event handling inner function:-
*/</span>
e = e||window.event;
<span class="commentJS">/* The event handler calls a method of the object - obj - with
the name held in the string - methodName - passing the now
normalised event object and a reference to the element to
which the event handler has been assigned using the - this -
(which works because the inner function is executed as a
method of that element because it has been assigned as an
event handler):-
*/</span>
return obj[methodName](e, this);
});
}
 
<span class="commentJS">/* This constructor function creates objects that associates themselves
with DOM elements whose IDs are passed to the constructor as a
string. The object instances want to arrange than when the
corresponding element triggers onclick, onmouseover and onmouseout
events corresponding methods are called on their object instance.
*/</span>
function DhtmlObject(elementId){
<span class="commentJS">/* A function is called that retrieves a reference to the DOM
element (or null if it cannot be found) with the ID of the
required element passed as its argument. The returned value
is assigned to the local variable - el -:-
*/</span>
var el = getElementWithId(elementId);
<span class="commentJS">/* The value of - el - is internally type-converted to boolean for
the - if - statement so that if it refers to an object the
result will be true, and if it is null the result false. So that
the following block is only executed if the - el - variable
refers to a DOM element:-
*/</span>
if(el){
<span class="commentJS">/* To assign a function as the element's event handler this
object calls the - associateObjWithEvent - function
specifying itself (with the - this - keyword) as the object
on which a method is to be called and providing the name of
the method that is to be called. The - associateObjWithEvent
- function will return a reference to an inner function that
is assigned to the event handler of the DOM element. That
inner function will call the required method on the
javascript object when it is executed in response to
events:-
*/</span>
el.onclick = associateObjWithEvent(this, "doOnClick");
el.onmouseover = associateObjWithEvent(this, "doMouseOver");
el.onmouseout = associateObjWithEvent(this, "doMouseOut");
...
}
}
DhtmlObject.prototype.doOnClick = function(event, element){
... <span class="commentJS">// doOnClick method body</span>.
}
DhtmlObject.prototype.doMouseOver = function(event, element){
... <span class="commentJS">// doMouseOver method body.</span>
}
DhtmlObject.prototype.doMouseOut = function(event, element){
... <span class="commentJS">// doMouseOut method body.</span>
}
</pre>
 
<p>
And so any instances of the <code>DhtmlObject</code> can associate themselves
with the DOM element that they are interested in without any need
to know anything about how they are being employed by other code,
impacting on the global namespace or risking clashes with other
instances of the <code>DhtmlObject</code>.
</p>
 
<h3><a name="clEncap" id="clEncap">Example 3: Encapsulating Related Functionality</a></h3>
 
<p>
Closures can be used to create additional scopes that can be used to
group interrelated and dependent code in a way that minimises the risk
of accidental interaction. Suppose a function is to build a string and
to avoid the repeated concatenation operations (and the creation of
numerous intermediate strings) the desire is to use an array to store
the parts of the string in sequence and then output the results using
the <code>Array.prototype.join</code> method (with an empty string as its argument).
The array is going to act as a buffer for the output, but defining it
locally to the function will result in its re-creation on each
execution of the function, which may not be necessary if the only
variable content of that array will be re-assigned on each function
call.
</p>
 
<p>
One approach might make the array a global variable so that it can be
re-used without being re-created. But the consequences of that will be
that, in addition to the global variable that refers to the function
that will use the buffer array, there will be a second global property
that refers to the array itself. The effect is to render the code less
manageable, as, if it is to be used elsewhere, its author has to remember
to include both the function definition and the array definition. It
also makes the code less easy to integrate with other code because
instead of just ensuring that the function name is unique within the
global namespace it is necessary to ensure that the Array on which it
is dependent is using a name that is unique within the global
namespace.
</p>
 
<p>
A Closure allows the buffer array to be associated (and neatly
packaged) with the function that is dependent upon it and
simultaneously keep the property name to which the buffer array as
assigned out of the global namespace and free of the risk of name
conflicts and accidental interactions.
</p>
 
<p>
The trick here is to create one additional execution context by
executing a function expression in-line and have that function
expression return an inner function that will be the function that is
used by external code. The buffer array is then defined as a local
variable of the function expression that is executed in-line. That only
happens once so the Array is only created once, but is available to
the function that depends on it for repeated use.
</p>
 
<p>
The following code creates a function that will return a string of
<span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span>, much of which is constant, but those constant character
sequences need to be interspersed with variable information provided
as parameter to the function call.
</p>
 
<p>
A reference to an inner function object is returned from the in-line
execution of a function expression and assigned to a global variable
so that it can be called as a global function. The buffer array is
defined as a local variable in the outer function expression. It is
not exposed in the global namespace and does not need to be re-created
whenever the function that uses it is called.
</p>
 
<pre>
<span class="commentJS">/* A global variable - getImgInPositionedDivHtml - is declared and
assigned the value of an inner function expression returned from
a one-time call to an outer function expression.
 
That inner function returns a string of <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> that represents an
absolutely positioned DIV wrapped round an IMG element, such that
all of the variable attribute values are provided as parameters
to the function call:-
*/</span>
var getImgInPositionedDivHtml = (function(){
<span class="commentJS">/* The - buffAr - Array is assigned to a local variable of the
outer function expression. It is only created once and that one
instance of the array is available to the inner function so that
it can be used on each execution of that inner function.
 
Empty strings are used as placeholders for the date that is to
be inserted into the Array by the inner function:-
*/</span>
var buffAr = [
'&lt;div id="',
'', <span class="commentJS">//index 1, DIV ID attribute</span>
'" style="position:absolute;top:',
'', <span class="commentJS">//index 3, DIV top position</span>
'px;left:',
'', <span class="commentJS">//index 5, DIV left position</span>
'px;width:',
'', <span class="commentJS">//index 7, DIV width</span>
'px;height:',
'', <span class="commentJS">//index 9, DIV height</span>
'px;overflow:hidden;\"&gt;&lt;img src=\"',
'', <span class="commentJS">//index 11, IMG URL</span>
'\" width=\"',
'', <span class="commentJS">//index 13, IMG width</span>
'\" height=\"',
'', <span class="commentJS">//index 15, IMG height</span>
'\" alt=\"',
'', <span class="commentJS">//index 17, IMG alt text</span>
'\"&gt;&lt;\/div&gt;'
];
<span class="commentJS">/* Return the inner function object that is the result of the
evaluation of a function expression. It is this inner function
object that will be executed on each call to -
getImgInPositionedDivHtml( ... ) -:-
*/</span>
return (function(url, id, width, height, top, left, altText){
<span class="commentJS">/* Assign the various parameters to the corresponding
locations in the buffer array:-
*/</span>
buffAr[1] = id;
buffAr[3] = top;
buffAr[5] = left;
buffAr[13] = (buffAr[7] = width);
buffAr[15] = (buffAr[9] = height);
buffAr[11] = url;
buffAr[17] = altText;
<span class="commentJS">/* Return the string created by joining each element in the
array using an empty string (which is the same as just
joining the elements together):-
*/</span>
return buffAr.join('');
}); <span class="commentJS">//:End of inner function expression.</span>
})();
<span class="commentJS">/*^^- :The inline execution of the outer function expression. */</span>
</pre>
 
<p>
If one function was dependent on one (or several) other functions, but
those other functions were not expected to be directly employed by any
other code, then the same technique could be used to group those
functions with the one that was to be publicly exposed. Making a
complex multi-function process into an easily portable and encapsulated
unit of code.
</p>
 
<h3><a name="clOtE" id="clOtE">Other Examples</a></h3>
 
<p>
Probably one of the best known applications of closures is
<a href="http://www.crockford.com/javascript/private.html">Douglas
Crockford's technique for the emulation of private instance variables
in ECMAScript objects</a>. Which can be extended to all sorts of
structures of <dfn>scope</dfn> contained nested accessibility/visibility, including
<a href="http://myweb.tiscali.co.uk/cornford/js_info/private_static.html">
the emulation of private static members for ECMAScript objects</a>.
</p>
 
<p>
The possible application of closures are endless, understanding how
they work is probably the best guide to realising how they can be
used.
</p>
 
<h2 id="clAc">Accidental Closures</h2>
 
<p>
Rendering any inner function accessible outside of the body of the
function in which it was created will form a closure. That makes
closures very easy to create and one of the consequences is that
javascript authors who do not appreciate closures as a language feature
can observe the use of inner functions for various tasks and employ
inner functions, with no apparent consequences, not realising that
closures are being created or what the implications of doing that are.
</p>
 
<p>
Accidentally creating closures can have harmful side effects as the
following section on the IE memory leak problem describes, but they can
also impact of the efficiency of code. It is not the closures
themselves, indeed carefully used they can contribute significantly
towards the creation of efficient code. It is the use of inner
functions that can impact on efficiency.
</p>
 
<p>
A common situation is where inner functions are used is as event
handlers for DOM elements. For example the following code might be used
to add an onclick handler to a link element:-
</p>
 
<pre>
<span class="commentJS">/* Define the global variable that is to have its value added to the
- href - of a link as a query string by the following function:-
*/</span>
var quantaty = 5;
<span class="commentJS">/* When a link passed to this function (as the argument to the function
call - linkRef -) an onclick event handler is added to the link that
will add the value of a global variable - quantaty - to the - href -
of that link as a query string, then return true so that the link
will navigate to the resource specified by the - href - which will
by then include the assigned query string:-
*/</span>
function addGlobalQueryOnClick(linkRef){
<span class="commentJS">/* If the - linkRef - parameter can be type converted to true
(which it will if it refers to an object):-
*/</span>
if(linkRef){
<span class="commentJS">/* Evaluate a function expression and assign a reference to the
function object that is created by the evaluation of the
function expression to the onclick handler of the link
element:-
*/</span>
linkRef.onclick = function(){
<span class="commentJS">/* This inner function expression adds the query string to
the - href - of the element to which it is attached as
an event handler:-
*/</span>
this.href += ('?quantaty='+escape(quantaty));
return true;
};
}
}
</pre>
 
<p>
Whenever the <code>addGlobalQueryOnClick</code> function is called a
new inner function is created (and a closure formed by its assignment).
From the efficiency point of view that would not be significant if the
<code>addGlobalQueryOnClick</code> function was only called once or
twice, but if the function was heavily employed many distinct function
objects would be created (one for each evaluation of the inner function
expression).
</p>
 
<p>
The above code is not taking advantage of the fact that inner functions
are becoming accessible outside of the function in which they are being
created (or the resulting closures). As a result exactly the same effect
could be achieved by defining the function that is to be used as the
event handler separately and then assigning a reference to that
function to the event handling property. Only one function object would
be created and all of the elements that use that event handler would
share a reference to that one function:-
</p>
 
<pre>
<span class="commentJS">/* Define the global variable that is to have its value added to the
- href - of a link as a query string by the following function:-
*/</span>
var quantaty = 5;
 
<span class="commentJS">/* When a link passed to this function (as the argument to the function
call - linkRef -) an onclick event handler is added to the link that
will add the value of a global variable - quantaty - to the - href -
of that link as a query string, then return true so that the link
will navigate to the resource specified by the - href - which will
by then include the assigned query string:-
*/</span>
function addGlobalQueryOnClick(linkRef){
<span class="commentJS">/* If the - linkRef - parameter can be type converted to true
(which it will if it refers to an object):-
*/</span>
if(linkRef){
<span class="commentJS">/* Assign a reference to a global function to the event
handling property of the link so that it becomes the
element's event handler:-
*/</span>
linkRef.onclick = forAddQueryOnClick;
}
}
<span class="commentJS">/* A global function declaration for a function that is intended to act
as an event handler for a link element, adding the value of a global
variable to the - href - of an element as an event handler:-
*/</span>
function forAddQueryOnClick(){
this.href += ('?quantaty='+escape(quantaty));
return true;
}
</pre>
 
<p>
As the inner function in the first version is not being used to exploit
the closures produced by its use, it would be more efficient not to use
an inner function, and thus not repeat the process of creating many
essentially identical function objects.
</p>
 
<p>
A similar consideration applies to object constructor functions. It is
not uncommon to see code similar to the following skeleton constructor:-
</p>
 
 
<pre>
function ExampleConst(param){
<span class="commentJS">/* Create methods of the object by evaluating function expressions
and assigning references to the resulting function objects
to the properties of the object being created:-
*/</span>
this.method1 = function(){
... <span class="commentJS">// method body.</span>
};
this.method2 = function(){
... <span class="commentJS">// method body.</span>
};
this.method3 = function(){
... <span class="commentJS">// method body.</span>
};
<span class="commentJS">/* Assign the constructor's parameter to a property of the object:-
*/</span>
this.publicProp = param;
}
</pre>
 
<p>
Each time the constructor is used to create an object, with
<code>new ExampleConst(n)</code>, a new set of function objects are
created to act as its methods. So the more object instances that are
created the more function objects are created to go with them.
</p>
 
<p>
Douglas Crockford's technique for emulating private members on
javascript objects exploits the closure resulting form assigning
references to inner function objects to the public properties of a
constructed object from within its constructor. But if the methods of
an object are not taking advantage of the closure that they will form
within the constructor the creation of multiple function objects for
each object instantiation will make the instantiation process slower
and more resources will be consumed to accommodate the extra function
objects created.
</p>
 
<p>
In that case it would be more efficient to create the function object
once and assign references to them to the corresponding properties of
the constructor's <code>prototype</code> so they may be shared by all
of the objects created with that constructor:-
</p>
 
<pre>
function ExampleConst(param){
<span class="commentJS">/* Assign the constructor's parameter to a property of the object:-
*/</span>
this.publicProp = param;
}
<span class="commentJS">/* Create methods for the objects by evaluating function expressions
and assigning references to the resulting function objects to the
properties of the constructor's prototype:-
*/</span>
ExampleConst.prototype.method1 = function(){
... <span class="commentJS">// method body.</span>
};
ExampleConst.prototype.method2 = function(){
... <span class="commentJS">// method body.</span>
};
ExampleConst.prototype.method3 = function(){
... <span class="commentJS">// method body.</span>
};
 
</pre>
<h2><a name="clMem" id="clMem">The Internet Explorer Memory Leak Problem</a></h2>
 
<p>
The Internet Explorer web browser (verified on versions 4 to 6 (6 is
current at the time of writing)) has a fault in its garbage collection
system that prevents it from garbage collecting ECMAScript and some
host objects if those host objects form part of a &quot;circular&quot;
reference. The host objects in question are any DOM Nodes (including
the document object and its descendants) and ActiveX objects. If a
circular reference is formed including one or more of them, then
none of the objects involved will be freed until the browser is closed
down, and the memory that they consume will be unavailable to the
system until that happens.
</p>
 
<p>
A circular reference is when two or more objects refer to each other in
a way that can be followed and lead back to the starting point. Such
as object 1 has a property that refers to object 2, object 2 has a
property that refers to object 3 and object 3 has a property that
refers back to object 1. With pure ECMAScript objects as soon as no
other objects refer to any of objects 1, 2 or 3 the fact that they only
refer to each other is recognised and they are made available for
garbage collection. But on Internet Explorer, if any of those objects
happen to be a DOM Node or ActiveX object, the garbage collection
cannot see that the circular relationship between them is isolated
from the rest of the system and free them. Instead they all stay in
memory until the browser is closed.
</p>
 
<p>
Closures are extremely good at forming circular references. If a
function object that forms a closure is assigned as, for example, and
event handler on a DOM Node, and a reference to that Node is assigned
to one of the Activation/Variable objects in its <dfn>scope chain</dfn> then a
circular reference exists.
<span class="scopeCh">DOM_Node.onevent -&gt;</span>
<span class="scopeCh">function_object.[[scope]] -&gt;</span>
<span class="scopeCh">scope_chain -&gt;</span>
<span class="scopeCh">Activation_object.nodeRef -&gt;</span>
<span class="scopeCh">DOM_Node</span>.
It is very easy to do, and a bit of browsing around a site that forms
such a reference in a piece of code common to each page can consume
most of the systems memory (possibly all).
</p>
 
<p>
Care can be taken to avoid forming circular references and remedial
action can be taken when they cannot otherwise be avoided, such as
using IE's onunload event to null event handling function
references. Recognising the problem and understanding closures
(and their mechanism) is the key to avoiding this problem with IE.
</p>
 
<p id="rToc">
<a href="faq_notes.html#toc">comp.lang.javascript FAQ notes T.O.C.</a>
</p>
 
<ul style="list-style-type:none;margin-top:2.5em;">
<li>Written by <span class="person">Richard Cornford</span>. March 2004.</li>
<li>With corrections and suggestions by:-<br>
<ul style="list-style-type:none;">
<li><span class="person">Martin Honnen</span>.</li>
<li><span class="person">Yann-Erwan Perio (Yep)</span>.</li>
<li><span class="person">Lasse Reichstein Nielsen</span>. (<a href="#clDefN">definition of closure</a>)</li>
<li><span class="person">Mike Scirocco</span>.</li>
<li><span class="person">Dr John Stockton</span>.</li>
<li><span class="person">Garrett Smith</span>.</li>
</ul>
</li>
</ul>
</body>
</html>
Property changes:
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: trunk/cljs/faq_notes/clj_posts.html
===================================================================
--- trunk/cljs/faq_notes/clj_posts.html (nonexistent)
+++ trunk/cljs/faq_notes/clj_posts.html (revision 43)
@@ -0,0 +1,1209 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+"http://www.w3.org/TR/html4/strict.dtd">
+<html lang="en">
+<head>
+<title>Notes on the comp.lang.javascript FAQ</title>
+<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+<link href="../../faq.css" rel="stylesheet" type="text/css">
+<link href="../notes.css" rel="stylesheet" type="text/css">
+<meta name="ROBOTS" content="NOINDEX, NOFOLLOW">
+<style type="text/css">
+.resourceList LI {
+ margin-bottom: 0.8em;
+}
+</style>
+</head>
+<body>
+
+<h1>Posting Questions and Replies to comp.lang.javascript</h1>
+<div id="faqNav">
+ <a href="../../">FAQ</a> &gt; <a href="../">FAQ Notes</a>
+
+</div>
+<ul>
+ <li><a href="#ps1Intro">Introduction</a></li>
+ <li><a href="#ps1Lang">Posting Language</a></li>
+ <li><a href="#ps1OToc">On and Off Topic Posting</a></li>
+ <li><a href="#ps1Txt">Plain-Text Only</a></li>
+ <li><a href="#ps1Post">Interleaved Posting, Bottom Posting and Not Top Posting.</a>
+ <ul>
+ <li><a href="#ps1InBPost">Interleaved Posting, Bottom Posting</a></li>
+ <li><a href="#ps1TopPs">Top Posting (don't)</a></li>
+ </ul>
+ </li>
+ <li><a href="#ps1Trim">What to Trim</a></li>
+ <li><a href="#ps1Marg">Margins and Line Wrapping</a>
+ <ul>
+ <li><a href="#ps1Mar">Margins</a></li>
+ <li><a href="#ps1Lw">Line Wrapping</a></li>
+ <li><a href="#ps1LwQu">Line Wrapping in Quoted Material</a></li>
+ </ul>
+ </li>
+ <li><a href="#ps1Code">General Code Postings, and when to use a URL</a></li>
+ <!-- <li><a href="#ps1Proof">Proof-read your message</a></li> -->
+ <li><a href="#ps1Quest">Well Asked Questions Get the Best Answers</a>
+ <ul>
+ <li><a href="#ps1QSub">Appropriate Use of the Subject Header</a></li>
+ <li><a href="#ps1QRes">Doing Your Own Research</a></li>
+ <li><a href="#ps1DontWork">&quot;It doesn't work&quot;</a></li>
+ <li><a href="#ps1CntX">Explain the Whole Context</a></li>
+ <li><a href="#ps1PR">Proof-Read your Questions</a></li>
+ </ul>
+ </li>
+ <!-- <li><a href="#ps1notHD">comp.lang.javascript is Not a Helpdesk</a></li> -->
+ <li><a href="#ps1AddR">Additional Reading</a></li>
+</ul>
+
+<h2 id="ps1Intro">Introduction</h2>
+<h3>Social Behavior</h3>
+
+<p>
+There may be several reasons for making posts to comp.lang.javascirpt
+but all valid reasons would be intended to elicit responses, preferably
+including responses form the many experienced and knowledgeable
+regular contributors to the group. The direction of communication is
+always one-to-many, which places the onus on the composer of a message
+to consider the many in their audience above any personal preferences.
+It is always in the best interest
+of someone posting to the group to recognise that the people whose
+responses will be of most value to them may have an attitude toward
+their behaviour on the group, and to try to ensure that it will not be
+a bad attitude.
+</p>
+
+<p>
+It is also always in the best interest of any poster to the group to do
+everything within their power to behave in a way that makes it quick
+and easy for the people they expect to answer their questions to read and follow
+their posts, understand their questions and problems and comprehend and
+test posted code. The people with the best answers are the most likely
+to be busy; too busy to be interested in unraveling a badly expressed
+problem from a mass of incomprehensibly formatted code amid a
+conversation that is hard to follow.
+</p>
+
+<p id="ps1Into_3">
+Usenet has been around for a long time now and has developed various
+conventions of its own. Conventions that have evolved to make
+communicating in the medium as easy and efficient as possible. They
+are not necessarily adhered to on all groups but where they are
+recognised they are definitely preferred. And comp.lang.javascript is
+a group where most of the regulars recognise many Usenet conventions
+and so the FAQ outlines them. This document is intended to provide
+additional detail on the subject.
+</p>
+
+<p id="ps1Into_4">
+Following those conventions and additionally posting with a
+consideration of the other points made on this page related more
+specifically to posting in comp.lang.javascript, will maximise the
+potential for any questions asked and posts made to elicit a useful
+response. At least in part because they make it quicker and easier for
+those interested in offering help to do so.
+</p>
+
+<h2 id="ps1Lang">Posting Language</h2>
+
+<p id="ps1Lang_1">
+comp.lang.javascript is the international javascript group. There are
+language specific javascript groups that could be expected to be
+carried by news servers within the countries concerned. There is,
+however, no English language specific javascript group so
+comp.lang.javascript serves that audience. As a result the vast
+majority of the conversation within the group is in English, and
+anyone with a javascript interest but incapable of reading/writing any
+language but English would choose comp.lang.javascript to read and post
+in. But there are no rules that say that English is the only language
+that is to be used.
+</p>
+
+<p id="ps1Lang_2">
+As an international group, comp.lang.javascript has contributors form
+around the world, many of whom speak/read/write English as a second or
+third (+) language. So a post made in any other language will stand a
+chance of falling within the linguistic capabilities of someone. But
+posts in English should be understandable to everyone, including those
+for whom English is their only language, and thus receive the most
+attention.
+</p>
+
+<p id="ps1Lang_3">
+Machine translation into English (and sometimes less skilled human
+translation) sometimes does not produce results that can be
+understood/followed by English speakers. When a bad translation into
+English is the only option it might be better for a poster to precede
+it with a version in their native language. (Faced with a post in a
+language that is not understood it is natural to scroll down to see
+if there is any accompanying javascript code that might explain the
+problem; a following English translation would be discovered along
+the way). A reader of the group who understands the language used
+may be able to contribute improvements to the English translation even
+if they cannot directly address the question raised.
+</p>
+
+<p id="ps1Lang_4">
+However, even though the most common language used in postings to
+comp.lang.javascript is English, the fact that the group is
+international and that English should not be expected to be the first
+language of contributors to the group means that the English used
+should be formally correct (to the best of the posters ability).
+Normal English sentence structure should be observed, particularly in
+terms of capitalisation (which serves to aid reading for everyone). But
+above all, shorthand abbreviations should not be used, no matter how
+common they may be in English speaking cultures, as they would not
+normally be part of the teaching of English as a foreign language. This
+applies especially to text-message shorthand as they are very much a
+product of local culture and circumstances in a way that is not
+relevant to Usenet as a medium or appropriate to an international
+newsgroup.
+</p>
+
+<p id="ps1Lang_5">
+In the context of an international forum it is also probably best to
+avoid references that may be ambiguous outside of a national context.
+Date formats are an obvious example, with the ISO 8601 <code>YYYY-MM-DD</code> format
+being more appropriate than any preferred local form. Also, references
+to national bodies by acronym alone will not necessarily convey
+sufficient meaning to an international audience.
+</p>
+
+<h2 id="ps1OToc">On and Off Topic Posting</h2>
+
+<p id="ps1OToc_1">
+ECMA 262 is the formal specification for ECMAScript, the
+standard adopted by javascript implementations and thus the
+specification for javascript.
+</p>
+
+<h3>ECMAScript and Browsers</h3>
+<p id="ps1OToc_2">
+As comp.lang.javascript deals with ECMAScript and ECMAScript was
+designed as a general scripting language for scripting any object
+model, questions relating to any application of ECMAScript are
+appropriate. The group has a general bias towards the use of
+ECMAScript in web browsers in an Internet context, and questions
+asked without additional qualification will tend to be assumed to
+be related to that environment and context. As a result it is a
+very good idea for questions asked that are not related to that
+default context; Intranet, other hosts, OS automation, etc., to
+include details of that context.
+</p>
+
+<h3 id="ps1OToc_3">Javascript (not Java)</h3>
+<p>
+Because of the name &quot;JavaScript&quot; being applied to the
+language early in its existence there is often confusion between
+javascript and the Java programming language. The two are distinct
+and very different languages. Questions relating to Java programming,
+Java Applets, Java Server Pages (JSP), etc., would be better asked in
+comp.lang.java.* groups. Only the use of ECMAScript to interact with,
+say, Java Applets would be on topic, and then the questions should
+relate to the ECMAScript aspect of the problem.
+</p>
+
+<h3 id="ps1OToc_4">Other Languages</h3>
+<p>
+Questions relating exclusively to other scripting languages,
+ mark-up languages ((x)<span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span>) and style sheets
+(<span class="initialism" title="Cascading Style Sheet"><abbr title="Cascading Style Sheet">CSS</abbr></span>, XSL) are off topic and should be addressed to more
+appropriate newsgroups.
+</p>
+
+<h3 id="ps1OToc_5">The FAQ</h3>
+<p>
+The comp.lang.javascript newsgroup may also validly become its own
+subject, particularly the content and maintenance of the FAQ resources.
+But as a subject that is most appropriately raised and discussed by
+the individuals who invest their time in the group rather than
+passers-by.
+</p>
+
+<h3 id="ps1OToc_6">Usenet Behavior (don't)</h3>
+<p>
+Usenet, and particularly appropriate behaviour on and for Usenet, is
+also often raised. This is largely unwelcome but inevitable. Hopefully
+this document should contribute to a reduction in that noise by stating
+the group's attitude towards Usenet postings in greater detail than can
+be accommodated in the FAQ proper.
+</p>
+
+<h3 id="ps1OToc_7">Spam (don't)</h3>
+<p>
+Other things that are off topic for the group include obvious things
+like pyramid and get rich quick schemes, commercial advertising (with
+some rare exceptions mentioned below), job adverts, spurious
+invitations to visit web sites and anything else that might be
+reasonably regarded as spam.
+</p>
+
+<h3>Announcements</h3>
+<p id="ps1OToc_8">
+Announcements of product releases and events of particular relevance
+to javascript are welcome but, for products no more often than once
+pre major release, and for events preferably only once and certainly
+not more often than at two month intervals leading up to the event.
+Be aware that product announcements (particularly commercial
+javascript) are likely to attract reviews, which should not be
+expected to be uncritical.
+</p>
+
+<h2 id="ps1Txt">Plain-Text Only</h2>
+
+<p id="ps1Txt_1">
+Messages are posted in plain-text. There is no requirement for Usenet
+newsreader software to recognise, support or display any other
+content type, such as <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span>, and it is felt that messages posted to
+comp.lang.javascript should be available to any and all newsreader
+software. Any form of attachments are also ruled out.
+</p>
+
+<p id="ps1Txt_2">
+It has also been observed that while most of the world may be happy
+to use the newsreader bundled with their operating system, experts in
+various aspects of computing will often go out and acquire software
+that they believe superior for the task they have for it. Meaning that
+the people best equipped to offer help in the group are also the people
+least likely to be using the newsreader that you are familiar with.
+The expectation should be that others are using software that conforms
+to the applicable standards and not that they are using software with
+any particular set of additional or &quot;enhanced&quot; features, no
+matter how common they may seem. Plain-text posts will be readable by
+everyone, other content types may be subject to more comment on the
+inappropriateness of the content type than answers intended to address
+the question raised.
+</p>
+
+<h2 id="ps1Post">Interleaved Posting, Bottom Posting and Not Top Posting</h2>
+
+<h3 id="ps1InBPost">Interleaved Posting, Bottom Posting</h3>
+
+<p id="ps1InBPost_1">
+The posting style in messages intended as responses to other messages
+is an area where a long established pattern of behaviour has been
+recognised as most appropriate for the medium and become an established
+convention.
+</p>
+
+<p id="ps1InBPost_2">
+Material quoted from the previous message is attributed to its author
+and indented with a marker character (usually &gt;). It is trimmed down
+to just sufficient to provide the context in which the response is made
+(marking the fact that an edit has been made with one of several
+common notations, such as: &lt;snip&gt;, [snip], [ ... ], etc.) and
+the responding text is placed <em>below</em> the quoted material
+to which it is responding, separated from it by a blank line.
+</p>
+
+<p id="ps1InBPost_3">
+If the response addresses several points from the previous message
+then the parts of the quoted text providing the context for each
+point are separated by the responses to each point. Producing an
+interleaved post. If the quoted material is in one block then the
+response text goes after it at the bottom. Producing a bottom post.
+</p>
+
+<p id="ps1InBPost_4">
+It is not possible to distinguish between bottom posting and an
+interleaved post that is only responding to one point in the previous
+message. Personally, I prefer interleaved responses but neither will
+result in an adverse reaction. The important points are that quoted
+material should be trimmed to the minimum that provides sufficient
+context and that responses should follow that quoted material.
+The conversation, and its chronological sequence, flows in the normal
+direction of reading; top to bottom.
+</p>
+
+<p id="ps1InBPost_5">
+Failing to quote any of the preceding message is not necessarily
+wrong, so long as the text posted makes sense without the preceding
+message, for example, by summarising the points being responded to.
+But generally it is easier to provide the context for a response with
+a quoted snippet. But responses need to have a context.
+</p>
+
+<h3 id="ps1TopPs">Top Posting (don't)</h3>
+
+<p id="ps1TopPs_1">
+Top posting is placing the response above the quoted material that is
+being responded to. The chronological sequence of conversation becomes
+the reverse of the normal top to bottom reading sequence and, without
+additional text summarising the points being responded to, it is
+difficult to determine exactly which points such a reply relates to.
+</p>
+
+<p id="ps1TopPs_2">
+The worst possible style of response posting is top posting over a full
+verbatim quote of the previous message, but even placing a response
+above a trimmed quote is wrong. It renders the conversational aspects
+of a response backwards, requiring people to scroll up and down to
+reconstruct the context of the response and generally making it hard
+work to understand the message. The answers come before the questions
+and the comments precede their subjects.
+</p>
+
+<p id="ps1TopPs_3">
+People do attempt to justify top posting. A common excuse made by top
+posters is that their newsreader places the cursor at the top of the
+message so that is the natural place to write the reply. That excuse
+is worthless as newsreader software does not dictate the style of
+posting and a cursor that starts at the top of a post does not have
+to stay there. Indeed it should not be expected to stay there, as the
+first responsibility of the respondent is to trim the quoted material
+down to just what is necessary to provide context for their response.
+A process that may reasonably be achieved by moving down through the
+quoted material deleting whatever is unneeded and marking those edits.
+And having done that the cursor will be at or near the bottom.
+</p>
+
+<p id="ps1TopPs_4">
+The other common excuse for top posting is that avoids excessive
+scrolling in order to find the response. The need for excessive
+scrolling in an interleaved or bottom posted message is most likely
+an indicator that the quoted material has not been suitably, or
+sufficiently, trimmed. But a top posters apparent desire to avoid
+scrolling is of no value to the regular users of Usenet who are
+accustomed to interleaved/bottom posting. They may take the top
+post as a preamble and still scroll down to see if any specific
+points have been responded to, not discovering that hey have wasted
+their time until they get to the bottom. A very short top post,
+without a blank line separating it from the following attribution
+line, may easily be missed by someone expecting the quoted material
+to come first, meaning that they do not discover where to look until
+they have scrolled to the bottom, and then they need to back scroll
+to the top. The perception is wrong, top posting results in much more
+unnecessary scrolling than it avoids, and that misperception impacts on
+regular user of Usenet; the very people whose help and co-operation is
+being sought.
+</p>
+
+<p id="ps1TopPs_5">
+<strong>Never top post to comp.lang.javascript</strong>. There is an
+established convention in posting styles on Usenet, and
+comp.lang.javascript. It is most efficient for everyone if newcomers
+follow that convention even if it seems strange to do so at first. In
+the long run it makes life easier for everyone, and the sooner that is
+recognised the less likelihood there is of being taken for a fool.
+</p>
+
+<h2 id="ps1Trim">What to Trim</h2>
+
+<p id="ps1Trim_1">
+As a general guide, quoted material should almost never exceed the
+text posted in response. Exceptions might occur when both consist
+of exactly one line or sentence, or maybe a short code block that
+only needs a one line comment.
+</p>
+
+<p id="ps1Trim_2">
+Deciding what to trim is a matter of judgment and takes a bit of
+practice to get right. There are few hard and fast rules and the best
+general advice has got to be to observe the behaviour of others
+positing to the group.
+</p>
+
+<p id="ps1Trim_3">
+It is necessary to preserve the context in
+which a response is made but some things can be trimmed automatically:
+Signatures (if present); the section at the end of a post (and they
+should always, and only, be at the end, no matter where any individual
+newsreader may try to insert them) which starts with a separator
+consisting of &quot;dash dash space newline(aka return)&quot; on a
+line of its own, followed by material that is not directly
+related to the post but may be of more general interest or related
+to the individual who makes the post, should <strong>always</strong>
+be trimmed from quoted material. It is never normally relevant to a
+posted response, but even if a signature is being directly commented
+upon it is vital to remove the signature separator at least, and best
+to trim anything it contains that is not being commented upon.
+</p>
+
+<p id="ps1Trim_4">
+In comp.lang.javascript there is rarely much point in quoting
+javascript code that is not being directly commented upon or
+corrected. The indenting character (and possible line wrapping)
+renders any quoted code syntactically invalid so anyone wanting
+to use the code will have to go back to the message in which it
+originally appeared anyway. That would certainly apply to a post
+wishing to thank someone who had provided a complete scripted
+demonstration for their efforts.
+</p>
+
+<p id="ps1Trim_5">
+No matter what gets trimmed the material that stays should not be
+altered in terms of spelling, words used and their order, etc. A
+quote should be a quote not an interpretation.
+</p>
+
+<h2 id="ps1Marg">Margins and Line Wrapping</h2>
+<h3 id="ps1Mar">Margins</h3>
+
+<p id="ps1Mar_1">
+A line in a plane text Usenet post could be quite long, and some
+newsreaders would automatically wrap that line to the window in
+which it was being displayed. Others would provide horizontal scroll
+bars (usually undesirable) and yet others may not be able to access
+characters beyond the 80<sup>th</sup> (unlikely these days). There
+are no rules for handling excessively long lines but Usenet is old
+and has lived through the time when 80 character wide displays were
+commonplace. Along the way it became the convention that Usenet posts
+should have lines no longer than between 70 and 80 characters. And
+that avoids the need for any specified requirement in the handling of
+long lines by newsreader software. Lines in that range are unlikely to
+need to be wrapped for display and will not normally generate
+horizontal scroll bars. It is also the case that humans generally
+(and sometimes strongly) prefer to read text that is no more than about
+80 character per line.
+</p>
+
+<p id="ps1Mar_2">
+It is widely recommended that newsreader software should be configured
+to automatically wrap at about 72 characters when posting, which works
+well for posted text but can be problematic for posting long URLs and
+particularly in our context, posted source code. Others suggest that
+software should not be allowed to wrap posted code at all and that the
+poster should always do it manually. In either case it is the
+individual composing the post that is responsible for, and should be in
+control of, the wrapping of the content to ensure that it is suitable
+for posting to the group.
+</p>
+
+<h3 id="ps1Lw">Line Wrapping</h3>
+
+<p id="ps1Lw_1">
+Most URLs are less than 72 character long anyway but some, such as
+references to Usenet articles in the archives at groups.google.com,
+are longer. Some newsreader software is smart enough to recognise a
+URL and not apply its default margin settings to them but in any event
+delimiting them with &quot;&lt;URL:&quot at the beginning and
+&quot;&gt;&quot; at the end (preferably with the URL separated from
+the delimiters with spaces) should be sufficient to indicate to a
+reader that a line wrapped URL will need some remedial action.
+</p>
+
+<p id="ps1Lw_2">
+Restricting margins to 72 characters usually does not need to affect
+the functionality of posted code either. Allowing a newsreader to
+line wrap posted code as it sees fit will usually render that code
+faulty (and difficult to read) and that will make it difficult for
+a reader to differentiate between problems within the original code
+and problems arising form line wrapping.
+</p>
+
+<h3 id="ps1Lw_3">Code Reformatting</h3>
+<p>
+Javascript (ECMAScript) is extremely tolerant of white space (including
+line breaks) within its source code. There are in fact only a couple of
+places where white space characters are not allowed. For example, a
+line break may not be placed between the <code>return</code> keyword
+and any expression that is to be returned. As a result it is almost
+always possible to spread a line of javascript that would exceed the
+newsreaders wrapping margin across two or more lines without affecting
+its functionality or syntactic correctness.
+</p>
+
+<p id="ps1Lw_4">
+One of the main reasons that Javascript is so tolerant of white space
+is to allow the structure of the source code (how the code is laid out
+in a text editor/post) to convey additional meaning (usually related to
+structure of the code/function/program) and maximise clarity for human
+readers. The breaking of long lines of source code across several lines
+should be done in a way that does not detract from the clarity of the
+code.
+</p>
+
+<h4 id="ps1Lw_5">Blocks</h4>
+<p>
+The main source code structuring consideration that adds clarity is
+block indenting. A block is defined with curly brackets <code>{</code>
+and <code>}</code> and represents a block statement (which may contain
+zero or more other statements). It is normal to indent the statements
+within a block by one tab character, though that tab is usually set to
+4 or fewer spaces (two spaces is frequently recommended) width as the
+normal default 8 spaces width is a bit
+too deep for most practical uses. However, <em>tab character should not be
+used for indention in Usenet posts at all</em> as newsreader default tab
+settings may often be 8 characters but may also be zero characters,
+defeating the purpose indentation in posted code entirely. Good text
+editors will usually offer a facility to convert tabs to any number of
+spaces, which can be used to prepare code for posting. Indenting in
+code posted to Usenet should be done with space characters. 4 or fewer
+(two is often recommended) per level of indentation.
+</p>
+
+<p id="ps1Lw_6">
+There are various common styles of block indenting, of which I prefer
+to leave the opening <code>{</code> at the end of the control statement
+(on the same line) and list the block contents as one statement per
+line, indented by 4 <em>or fewer</em> spaces, with the closing
+<code>}</code> on a new line indented so that it lines up vertically
+with the start of the control statement, e.g.:-
+</p>
+
+<pre id="ps1Lw_ex1">
+function doSomething(oArea){
+ var nArea = oArea.nWidth * oArea.nHeight;
+ var result = true;
+ if(!nArea){
+ removeRegion(oArea);
+ result = false;
+ }else if(oArea.nWidth &lt; oArea.nHeight){
+ result = oArea.reShape(nArea);
+ }
+ return result;
+}
+
+<span class="commentJS">/* The same function may also be commonly formatted:- */</span>
+
+function doSomething(oArea)
+{
+ var nArea = oArea.nWidth * oArea.nHeight;
+ var result = true;
+ if(!nArea)
+ {
+ removeRegion(oArea);
+ result = false;
+ }
+ else if(oArea.nWidth &lt; oArea.nHeight)
+ {
+ result = oArea.reShape(nArea);
+ }
+ return result;
+}
+
+<span class="commentJS">/* -or:- */</span>
+
+function doSomething(oArea)
+ {
+ var nArea = oArea.nWidth * oArea.nHeight;
+ var result = true;
+ if(!nArea)
+ {
+ removeRegion(oArea);
+ result = false;
+ }
+ else if(oArea.nWidth &lt; oArea.nHeight)
+ {
+ result = oArea.reShape(nArea);
+ }
+ return result;
+ }
+</pre>
+
+<p id="ps1Lw_7">
+It is not that important which style of block indenting is used,
+everyone has their own preferred style, but it is important that
+<em>a</em> style of block indenting is used in code posted to the
+group. In all cases the indenting serves to make the structure of
+the function apparent in the structure of the source code. It is
+an aid to human readers of the code and saves a great deal of time
+for anyone attempting to offer help and so needing to understand
+the code.
+</p>
+
+<p id="ps1Lw_8">
+Sometimes the line wrapping problem can be avoided by reducing the
+number of space characters by which the blocks are indented. However,
+if a statement must be broken across several lines
+it could be indented to a different level than it's own start, and it
+could also be indented at a different level to its block contents (if
+any). If block indenting is at, say, 4 space intervals then indenting a
+broken line at 1 to 3 characters should serve to make it clear that
+it is indenting separate from the general block structure of the
+code, e.g.:-
+</p>
+
+<pre id="ps1Lw_ex2">
+function getRootElement_OrDefault(deflt){
+ if((typeof document.compatMode == "string")&&
+ (document.compatMode.indexOf("CSS") != -1)&&
+ (document.documentElement)){ <span class="commentJS">//<< broken statement</span>
+ return document.documentElement;
+ }else if(document.body){
+ return document.body;
+ }else{
+ return deflt;
+ }
+}
+
+</pre>
+
+<p id="ps1Lw_9">
+Another alternative for formatting statements broken across lines
+might be to disregard the indenting on the left and line the code
+that belongs to the broken statement up on the right hand side.
+e.g.:-
+</p>
+
+<pre id="ps1Lw_ex3">
+this.position = function(){
+ var twiceSize;
+ if(--delay <= 0){
+ step();
+ if(((z+=fv) >= planeDepth)||
+ ((dy+dm) > windowCenterY)||
+ ((dx+dm) > windowCenterX)||
+ (v < 0)){ <span class="commentJS">//right aligned broken statement</span>
+ this.reset();
+ step();
+ }
+ div.top = (sy+(py*dy)-dm)+cssUnitsOrZero;
+ div.left = (sx+(px*dx)-dm)+cssUnitsOrZero;
+ divClip.height = (twiceSize = (dm << 1)+cssUnitsOrZero);
+ divClip.width = twiceSize;
+ }
+ next.position();
+};
+</pre>
+
+<p id="ps1Lw_10">
+Thus the ability to insert line breaks liberally throughout javascript
+source code allows almost all code to be formatted in a fully
+functional, well structured and clear way within the restricted
+margins appropriate in posts to comp.lang.javascript. Efforts put into
+preparing posted code to be clear and comprehensible to its Usenet
+audience will be rewarded. But it is important to start any formatting
+required with the actual code in use, rather than attempting to
+re-type it, in order not to introduce errors that are not present in
+the original and so have nothing to do with the original problem.
+Having prepared the formatting of the code to suite Usenet it is
+important to re-test it to ensure that it is still as functional, that
+no errors have been introduced and that it still exhibits whatever
+behaviour it was that motivated the post in the first place.
+</p>
+
+<h3 id="ps1LwQu">Line Wrapping in Quoted Material</h3>
+
+<p id="ps1LwQu_1">
+If a news post has been wrapped at, say, 72 characters and it is
+responded to then the indenting character used to mark quoted material
+will add to the length of that line. Maybe pushing it over the length
+at which the reply will be wrapped. The result, if posted without
+adjustment, may look something like this:-
+</p>
+
+<pre id="ps1LwQu_ex1">
+An example OP wrote:
+> A long line of text quoted from the previous post, that was wrapped
+at
+> 72 characters in that post but has been extended to 74 characters
+long
+> lines because of the addition of the indenting characters that mark
+it
+> as a quotation, but has been re-wrapped to 72 characters in the
+posted
+> follow-up that is quoting it.
+
+The comment posted in response to the material quoted above. Originally
+wrapped in the response at 72 characters.
+</pre>
+
+<p id="ps1LwQu_2">
+The effect is that the words &quot;at&quot;, &quot;long&quot;,
+&quot;it&quot; and &quot;posted&quot; are no
+longer marked as part of the quotation but instead appear to be badly
+formatted and meaningless comments on that quoted material. Which has
+itself gained the appearance of being incompetently trimmed. The effect
+escalates with additional responses, loosing more meaning and becoming
+less and less clear as to whom any particular part of the text is
+attributable.
+</p>
+
+<pre id="ps1LwQu_ex2">
+The First Responder wrote:
+> An example OP wrote:
+>> The First Responder wrote:
+>>> An example OP wrote:
+>>>> A long line of text quoted from the previous post, that was
+wrapped
+>>> at
+>>>> 72 characters in that post but has been extended to 74 characters
+>>> long
+>>>> lines because of the addition of the indenting characters that
+mark
+>>> it
+>>>> as a quotation, but has been re-wrapped to 72 characters in the
+>>> posted
+>>>> follow-up that is quoting it.
+>>>
+>>> The comment posted in response to the material quoted above.
+>> Originally
+>>> wrapped in the response at 72 characters.
+>
+>> This response is the OP's reply to the comments on the original
+>> post. It quoted the previous posts in full and was wrapped at 72
+>> characters.
+>
+>And the original responder added this.
+
+The conversation ended with the OP thanking the responder for their
+comments. (but who said what?)
+</pre>
+
+<p id="ps1LwQu_3">
+The solution is to be aware that this may happen and re-wrap that
+quoted material so that it is not effected by the automatic line
+wrapping when a post is sent, or to increase the wrapping margins by
+the number of characters inserted to mark a quotation (so long as the
+result does not exceed 80 characters). Some newsreader software can
+handle this automatically, and add on software exists for other
+products (such as OE), but ultimately the responsibility for properly
+marking and attributing quoted material belongs with the individual
+making the post.
+</p>
+
+<p id="ps1LwQu_4">
+If the two had taken the effect of the progressive lengthening of lines
+in quoted material into account the result would have looked like
+this:-
+</p>
+
+<pre id="ps1LwQu_ex3">
+The First Responder wrote:
+> An example OP wrote:
+>> The First Responder wrote:
+>>> An example OP wrote:
+>>>> A long line of text quoted from the previous post, that was
+>>>> wrapped at 72 characters in that post but has been extended to 74
+>>>> characters long lines because of the addition of the indenting
+>>>> characters that mark it as a quotation, but has been re-wrapped to
+>>>> 72 characters in the posted follow-up that is quoting it.
+>>>
+>>> The comment posted in response to the material quoted above.
+>>> Originally wrapped in the response at 72 characters.
+>
+>> This response is the OP's reply to the comments on the original
+>> post. It quoted the previous posts in full and was wrapped at 72
+>> characters.
+>
+>And the original responder added this.
+
+The conversation ended with the OP thanking the responder for their
+comments.
+</pre>
+
+<p id="ps1LwQu_5">
+It would have been clear form the number of quote indicating characters
+who exactly had said what and the quoted material would have been
+easier to read and understand. Though in practice there probably should
+have been much more trimming along the way as the whole conversation
+would probably not have been needed to show the context of each
+response.
+</p>
+
+
+<h2 id="ps1Code">General Code Postings, and when to use a URL</h2>
+
+<p id="ps1Code_1">
+Often a question cannot usefully be answered without being accompanied
+with javascript source code. Even a very detailed explanation of a
+process will not tend to narrow the possibilities down to just one
+method, and deciding whether a reported effect is due to a
+characteristic of an execution environment or code that is taking the
+wrong approach cannot be done without seeing the source code.
+</p>
+
+<p id="ps1Code_2">
+In some cases small snippets of code, say an individual function's
+definition, might be sufficient. Though it is usually necessary to know
+how such a function is being called and what arguments it is using. But
+ideally questions should be accompanied by an easily testable example
+that demonstrates the characteristics that provoked the question.
+</p>
+
+<p id="ps1Code_3">
+Easily testable because there is no better aid to debugging than being
+able to reproduce a problem. Time spent turning a snippet of code into
+testable web page (or whatever) is not rewarded if the results do not
+exhibit the problem described. And asking many people to repeat that
+process when it could have been done by the questioner once, in a way
+that guaranteed a demonstration of the problem, is not a good use of
+the group or the time of its participants.
+</p>
+
+<p id="ps1Code_4">
+However, posting the entire source code of a web page that happens to
+include the problematic script is rarely the answer. For one thing web
+pages often import <span class="initialism" title="Cascading Style Sheet"><abbr title="Cascading Style Sheet">CSS</abbr></span>, other script files and graphics (the latter
+simply could not be posted to the group). But web pages also often
+consist of large amounts of <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span>, which would require careful
+re-wrapping to fit within the posting margins and be left correct, and
+much of the <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> would be irrelevant to the post.
+</p>
+
+<p id="ps1Code_5">
+There is also the question of bandwidth in transmission and capacity in
+storage. Every post is stored, at least for a time, on every news server
+carrying the group world wide and usually also on the hard disk of
+everyone who reads the group. And to get from server to server, and
+eventually to the many readers, it must be transmitted, consuming
+bandwidth related to the size of the post. The more irrelevant
+information that any post contains the more those resources are wasted
+(this is also a reason for appropriate trimming of quoted material).
+</p>
+
+<p id="ps1Code_6">
+The comp.lang.javascript FAQ makes the injunction that posting code of
+more than 500 lines is unacceptable. That is the theoretical upper
+limit that should never be exceeded, but a post of even half that
+length would have to be exceptional.
+</p>
+
+<p id="ps1Code_7">
+The easiest way of demonstrating a problem in context without posting
+excessive amounts of code and <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> is to make a page that exhibits the
+problem available online and post the URL of that page along with the
+question. Possibly accompanied by a snippet of the code highlighting
+the suspected cause.
+</p>
+
+<p id="ps1Code_8">
+The circumstances under which making a page that demonstrates the
+problem available online is advisable are, whenever that page is
+interacting within a frameset, or whenever images play a significant
+part in a problem. As those circumstances are time consuming to
+reproduce from posted code and cannot always be recreated for testing.
+But any request to have people examine excessive amounts of code
+and/or <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> should also be made available on line instead of in a post.
+</p>
+
+<p id="ps1Code_9">
+Unfortunately not all participants in the group are viewing Usenet in a
+way that makes easily following a URL to an example page viable. Often
+downloading new Usenet posts as a batch and then viewing them off line.
+Re-connecting to view an example page is not always desirable (due to
+local conditions, slow modem connections and potential associated
+expense) and can be unrewarding if the page viewed is a mush of <abbr title="What You See Is What You Get">WYSIWYG</abbr>
+generated bloated <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span>-like noise. Where it takes a considerable time
+to even locate the cause of what may still turn out to be a trivial
+problem.
+</p>
+
+<p id="ps1Code_10">
+Then again there are people using the group who much prefer examples to
+be available online. Either way what is not wanted is for questions to
+be asked without making the corresponding code available in some way,
+or the posting of excessive amounts of code.
+</p>
+
+<p id="ps1Code_11">
+A good compromise, and a valuable debugging technique, is the creation
+of a demonstration test-case page. A page containing no more than
+sufficient <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> and javascript to allow others to reproduce the problem
+and see the relevant code without anything extraneous. Such a test-case
+page would almost always be short enough to post with the question
+(properly formatted) and could additionally be made available online for
+the convenience of those that would prefer to use a URL to load it
+directly into a browser for testing.
+</p>
+
+<p id="ps1Code_12">
+Creating such a test-case page can be valuable in itself as attempting
+to reduce a problem from a larger context to an isolated demonstration
+will often reveal the cause of that problem along the way. The act of
+cutting out what initially seems irrelevant often reveals that the
+problem in fact results form an unexpected interaction with something
+that was assumed to be unconnected. And if the problem can be
+demonstrated in isolation then it is relatively easy for readers of the
+question to reproduce the problem and identify its cause, resulting in
+less discussion of superfluous issues and usually a quicker resolution
+of the question.
+</p>
+
+<p id="ps1Code_13">
+It is very important to test test-case pages prior to posting them to
+ensure that they do indeed exhibit the characteristic that motivated
+the question. At least if you want to be taken seriously in future. And
+when such a test-case is posted to the group it should be formatted and
+indented to facilitate the essayist reading of the code and testing by
+no more than copying the page into a text editor and saving it locally
+as a <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> file.
+</p>
+
+
+<h2 id="ps1Quest">Well Asked Questions Get the Best Answers</h2>
+
+<p id="ps1Quest_1">
+Beyond any considerations of posting style and formatting, the quality
+of questions asked has a considerable impact upon the number and
+quality of answers given, and the time taken to elicit a useful
+response. Vague questions are likely to be answered with requests for
+clarification. Terse general questions are likely to elicit yes or no
+answers (often both). And questions that have been asked, and well
+answered, before (especially frequently or in the recent past) are as
+likely as not to be ignored.
+</p>
+
+<p id="ps1Quest_2">
+When asking a question it would almost always be a good idea to put
+yourself in the position of the reader of the question, read it back to
+yourself and ask yourself; Does this question actually ask what I
+want to know, and is it sufficiently clear and detailed to elicit that
+answer?
+</p>
+
+<p id="ps1Quest_3">
+The following is a short list of recurring features of badly asked
+questions:-
+</p>
+
+
+<h3 id="ps1QSub">Appropriate Use of the Subject Header</h3>
+
+<p id="ps1QSub_1">
+Another Usenet convention holds that the Subject header should not be
+expected to be available to a reader of any message. While it is
+unlikely that there are any newsreaders currently in use in which the
+user is not presented with the Subject header, it remains
+inappropriate to ask a question in the subject header (or to assume
+that its contents will provide supplementary information about a
+question) and doing so is as likely to invoke a lesson in Usenet
+etiquette as an answer to the question. But a question is not really
+a subject anyway. The subject should describe what the question is
+in relation to, and is useful for archive searching and
+categorisation rather than as a means of communication.
+</p>
+
+<p id="ps1QSub_2">
+Any question asked should always appear in the body of the post, and in
+a form that does not assume the availability of the Subject header to
+the reader.
+</p>
+
+<p id="ps1QSub_3">
+The Subject header should also not be wasted. Placing &quot;please
+help&quot; and the like in the subject header is unwelcome and
+counterproductive. Take the opportunity to construct a Subject
+header that states the type of the problem, what it relates to.
+Subject headers that state the real subject will attract the
+attention of people with a special interest in that subject,
+exactly those people best able to offer help.
+</p>
+
+<h3 id="ps1QRes">Doing Your Own Research</h3>
+
+<p id="ps1QRes_1">
+Many questions, at least the questions literally asked, could quickly
+be answered with a little research, and the chances are that regulars
+on the group know how easily those answers could have been found with
+a little effort. The group is not intended to be a vending machine for
+trivial information about javascript, that wouldn't be an interesting
+group to participate in.
+</p>
+
+<p id="ps1QRes_2">
+On the other hand, evidence that some effort has been put into
+researching a problem before asking a question tends to be looked upon
+kindly (though claiming to have exhausted all lines of research when that
+is obviously not the case would have the opposite effect).
+</p>
+
+<p id="ps1QRes_3">
+The obvious first place to look for answers is in
+<a href="../clj_faq.html">the group's FAQ</a>. That will
+mean reading all of the FAQ because the answers to some problems (or
+sufficient clues to those answers) will be found within the answers to
+seemingly unrelated questions, or the resources linked to from the FAQ.
+That in itself is a fairly big task, but if not undertaken will just
+result in questions being answered with references back to the FAQ.
+There is also a Usenet convention that whenever a newsgroup
+(particularly technical groups) provides a FAQ resource, that FQA should
+be read by anyone wishing to post to the group <em>prior</em> to making
+their first post. So reading the FAQ is <em>not optional</em> anyway.
+</p>
+
+<p id="ps1QRes_4">
+The Internet provides a massive resource for researching virtually any
+question, and particularly questions relating to computing. Search
+engines are the primary research tool and among those Google search is
+extremely useful. But when a question relates to javascript in a way
+that indicates that it may be suitable to be asked on
+comp.lang.javascript the best place to research the question is
+<a href="http://groups.google.com/groups?q=comp.lang.javascript">
+groups.google.com</a>, as that resource holds a searchable archive of
+almost all postings ever made to the group. There is an
+<a href="http://groups.google.com/advanced_group_search?group=comp.lang.javascript">
+&quot;Advanced Search&quot; page</a>, where entering
+&quot;comp.lang.javascript&quot; in the Newsgroup field and suitable keywords
+in the other fields provided will return all messages posted to the group
+that match the search criteria. As most questions will have been asked
+before many answers can be obtained from the groups.google.com archives.
+But be aware of the date of posts found as the archive goes back to
+1996 and some things have changed over the intervening years.
+</p>
+
+<p id="ps1QRes_5">
+Reading back over recent posts to the group, for a minimum of a week
+and preferably more than a month will avoid the need to re-ask a
+question that has been asked and answered in recent memory. Not all
+news servers will hold all messages over that period so
+<a href="http://groups.google.com/groups?q=comp.lang.javascript">
+the group archives at groups.google.com</a> can be useful in this
+respect also.
+</p>
+
+<h3 id="ps1DontWork">&quot;It doesn't work&quot;</h3>
+
+<p id="ps1DontWork_1">
+People don't tend to question code that
+does exactly what they want it to do. Sometimes they may ask how it
+does exactly what they want but generally it is superfluous to state
+that code that does not address a situation doesn't work.
+</p>
+
+<p id="ps1DontWork_2">
+To start with computer code always does exactly what is asked of it,
+that is the nature of computers. So it does &quot;work&quot;, it is
+just that it doesn't do what is wanted of it. And that is a problem
+because code that does not do something that is wanted of it cannot
+itself explain what that something was.
+</p>
+
+<p id="ps1DontWork_3">
+It is the task of a human designer to decide what is wanted form code,
+to specify the task. The reader of a question can do no more than
+guess as to the task unless the questioner explains the specification
+for the code, and that specification needs to be specific. That
+information is needed when assessing what would qualify as
+&quot;works&quot; in the context of the question.
+</p>
+
+<p id="ps1DontWork_4">
+But in addition to knowing what would qualify as working it is also
+necessary to know in what way code is failing to work. There is a big
+difference between code that appears to do nothing when executed, code
+that does something undesirable in addition to what is expected of it
+and code that does something else entirely.
+</p>
+
+<p id="ps1DontWork_5">
+Instead of stating the self-evident &quot;It doesn't work&quot;, the
+posters of questions should attempt to provide answers to:-
+</p>
+
+<dl id="ps1DontWork_df">
+ <dt id="ps1DontWork_p1">1. What you have done?</dt>
+
+ <dd id="ps1DontWork_d1">Providing access the code (possibly in the form of a test
+ case), explaining the steps required to initiate the
+ undesirable effect and the environments (usually web
+ browsers) where the problem has been observed, so that it
+ can be reproduced and tested.
+ <dd>
+
+ <dt id="ps1DontWork_p2">2. What you expected to happen?</dt>
+
+ <dd id="ps1DontWork_d2">Both specifically in the case of the code under discussion and
+ generally with regard to the design specification.
+ <dd>
+
+ <dt id="ps1DontWork_p3">3. What really happened?</dt>
+
+ <dd id="ps1DontWork_d3">What was observed to happen and any error messaged generated.
+ So that when (and if) the problem is reproduced in testing it
+ is possible to identify it as the effect under discussion.
+ <dd>
+</dl>
+
+<h3 id="ps1CntX">Explain the Whole Context</h3>
+
+<p id="ps1CntX_1">
+The context in which a question is asked or a problem exists is very
+important to the type of answers given or solutions proposed. Beyond
+the obvious required details such as the execution host(s), scripts
+used and how they are used, There are details like whether a project
+is for the Internet or an Intranet. Because on comp.lang.javascript
+the default assumption is that the context will be browser scripting
+for the Internet, many approaches/solutions are ruled out, but some may
+be completely reasonable and practical in the more restricted context
+of a company Intranet (or on more controlled hosts such as the windows
+scripting host or server-side javascript).
+</p>
+
+<p id="ps1CntX_2">
+There have been many occasions where many answers to questions have
+stressed the unsuitability of particular approaches to use on the
+Internet only for the original questioner to respond by explaining
+that they don't apply because their context is an Intranet. That
+wastes the time of everyone who composed a response to the original
+question; if they had been in possession of the real context from the
+outset they could have got on with proposing/discussing solutions that
+were appropriate, or moved on to something more interesting.
+</p>
+
+<p id="ps1CntX_3">
+But the full context of a question goes beyond such details and answers
+the question: why? Often a question will be asking about a particular
+approach that, to the questioner, is a perceived solution to a problem.
+The answer to the question why would explain what that problem is, and
+knowing what that problem is will allow respondents to assess the
+suitability of the approach at addressing the problem and possibly
+suggest other, and superior, solutions. There is very little that is
+genuinely new and unique, whatever the wider problem is the chances are
+that someone will be familiar with it and be in a position to identify
+the best solution (even if that is just confirming that the proposed
+solution is the best available). Questions raised on the group should
+always include the answer to the question: why?
+</p>
+
+<h3 id="ps1PR">Proof-Read your Questions</h3>
+
+<p id="ps1PR_1">
+Proof-read your message two or three times before posting. Ensure that
+it is as error free as possible and does convey the question and
+provide all of the necessary information in a way that will not be
+subject to misinterpretation.
+</p>
+
+<!-- <h2><a name="ps1notHD" id="ps1notHD">comp.lang.javascript is Not a Helpdesk</a></h2>
+
+<p id="ps1notHD_1">
+The comp.lang.javascript newsgroup is a discussion forum on the subject
+of ECMAScript (javascript). It is not a helpdesk and its participants
+make their contributions voluntarily in their own time and with their
+own resources for whatever reasons they see fit. Just because the
+majority of the discussion starts with someone posting a question,
+often asking for help with some aspect of javascript, does not mean
+that anyone should have any expectation of receiving any help or
+assistance from any ensuing discussion. So, although help and
+assistance is often (if not usually) offered during the following
+discussion, that is just a positive side effect of the group and not
+its reason for existing.
+</p>
+
+<p id="ps1notHD_2">
+The real benefit of the group goes to its regular participants, who,
+in participating in the discussion, attempting to address the diverse
+situations and problems raised and exposing their code to critical
+public scrutiny, get to hone their code authoring and script design
+skills and knowledge with the active assistance and critical feed-back
+of their peers.
+</p>
+
+<p id="ps1notHD_3">
+The whole process would not work as well if people did not post
+questions relating to a diversity of problem situations to the group
+in the hope of getting some assistance, and people would never do that
+if there were not a good chance of actually getting assistance. But the
+people posting such questions need to remember that they have no right
+to assistance, and cannot demand, or even expect it. Instead, wanting
+to take advantage of the potentially beneficial side effect of the
+existence of the group, they should encourage the group to give them
+assistance, by making doing so as easy and convenient as possible. The
+preceding document is intended to make it as clear as possible how to
+go about achieving that aim.
+</p> -->
+
+<h2 id="ps1AddR">Additional Reading</h2>
+
+<ul class="resourceList" id="ps1AddR_l">
+ <li><a href="http://www.cs.tut.fi/~jkorpela/usenet/dont.html">The seven don'ts of Usenet<br>http://www.cs.tut.fi/~jkorpela/usenet/dont.html</a></li>
+ <li><a href="http://oakroadsystems.com/genl/unice.htm">Playing Nice on Usenet<br>http://oakroadsystems.com/genl/unice.htm</a></li>
+ <li><a href="http://www.netmeister.org/news/learn2quote2.html">How do I quote correctly in Usenet? - Quoting and Answering<br>http://www.netmeister.org/news/learn2quote2.html</a></li>
+ <li><a href="http://www.xs4all.nl/%7ewijnands/nnq/nquote.html">Quoting Style in Newsgroup Postings<br>http://www.xs4all.nl/%7ewijnands/nnq/nquote.html </a></li>
+ <li><a href="http://www.cs.tut.fi/~jkorpela/usenet/xpost.html">Why and how to crosspost<br>http://www.cs.tut.fi/~jkorpela/usenet/xpost.html</a></li>
+ <li><a href="http://kb.indiana.edu/data/affn.html?cust=12244">How can I post a message to more than one Usenet newsgroup?<br>http://kb.indiana.edu/data/affn.html?cust=12244</a></li>
+ <li><a href="http://catb.org/%7Eesr/faqs/smart-questions.html">How To Ask Questions The Smart Way<br>http://catb.org/%7Eesr/faqs/smart-questions.html</a></li>
+ <li><a href="http://www.chiark.greenend.org.uk/~sgtatham/bugs.html">How to Report Bugs Effectively<br>http://www.chiark.greenend.org.uk/~sgtatham/bugs.html</a></li>
+</ul>
+</body>
+</html>
/trunk/cljs/faq_notes/clj_posts.html
Property changes:
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: trunk/cljs/faq_notes/type_convert.html
===================================================================
--- trunk/cljs/faq_notes/type_convert.html (nonexistent)
+++ trunk/cljs/faq_notes/type_convert.html (revision 43)
@@ -0,0 +1,1319 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+"http://www.w3.org/TR/html4/strict.dtd">
+<html lang="en">
+<head>
+ <title>Javascript Type-Conversion</title>
+ <meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+<link href="../../faq.css" rel="stylesheet" type="text/css">
+<link href="../notes.css" rel="stylesheet" type="text/css">
+<style type="text/css">
+td {
+ text-align:center;
+}
+pre.st {
+ background-color:#EEEEFF;
+ margin:0px;
+ padding:0px;
+ text-align:left;
+ border:0px none #EEEEFF;
+}
+caption {
+ font-weight:bold;
+}
+th, td {
+ vertical-align:baseline;
+ background-color:#EEEEFF;
+ color:#000000;
+ white-space:nowrap;
+ padding:2px
+}
+.true {
+ color:#003444;
+ background-color:#E0FFE0;
+}
+.false {
+ color:#003444;
+ background-color:#FFE0E0;
+}
+table {
+ margin:1em 2.5em;
+}
+ </style>
+ </head>
+ <body>
+
+<h1>Javascript Type-Conversion</h1>
+<div id="faqNav">
+ <a href="/faq/">FAQ</a> &gt; <a href="/faq/notes/">FAQ Notes</a>
+</div>
+
+<ul>
+ <li><a href="#tcInt">Introduction</a></li>
+ <li><a href="#tcBool">Converting to Boolean</a></li>
+ <li><a href="#tcString">Converting to String</a></li>
+ <li><a href="#tcNumber">Converting to Number</a></li>
+ <li><a href="#tcParse">Parsing to Number</a>
+ <ul>
+ <li><a href="#tcParseFl">parseFloat</a></li>
+ <li><a href="#tcParseIn">parseInt</a></li>
+ <li><a href="#tcPrIntRx">parseInt with a radix argument</a></li>
+ </ul>
+ </li>
+ <li><a href="#tcToInt32">ToInt32</a></li>
+ <li><a href="#tcUserIn">Converting User Input</a>
+ <ul>
+ <li><a href="#tcRegEx">Regular expression examples</a></li>
+ </ul>
+ </li>
+</ul>
+
+<h2 id="tcInt">Introduction</h2>
+
+<p id="tcInt_1">
+Javascript (ECMAScript) is a loosely typed language. That does not mean
+that it has no data types just that the value of a variable or a Javascript
+object property does not need to have a particular type of value assigned
+to it, or that it should always hold the same type of value. Javascript
+also freely type-converts values into a type suitable for (or required by)
+the context of their use.
+</p>
+
+<p id="tcInt_2">
+Javascript being loosely typed and willing to type-convert still does not
+save the programmer from needing to think about the actual type of values
+that they are dealing with. A very common error in browser scripting, for
+example, is to read the value property of a form control into which the
+user is expected to type a number and then add that value to another
+number. Because the value properties of form controls are strings (even if
+the character sequence they contain represents a number) the attempt to
+add that string to a value, even if that value happens to be a number,
+results in the second value being type-converted into a string and
+concatenated to the end of the first string value from the from control.
+</p>
+
+<p id="tcInt_3">
+That problem arises from the dual nature of the <code>+</code> operator
+used for both numeric addition and string concatenation. With which the
+nature of the operation performed is determined by the context, where
+only if both operands are numbers to start with will the <code>+</code>
+operator perform addition. Otherwise it converts all of its operands to
+strings and does concatenation.
+</p>
+
+<p id="tcInt_4">
+The following discussion is illustrated with Javascript generated tables
+of values resulting from the conversion operations. The headers of those
+tables display the values as represented in the Javascript source code
+used rather than their internal representation. So, for example
+<code>123e-2</code> as a number was the character sequence typed into
+the source code, the interpreter reads that and generates the
+number value 1.23 from it for internal use. The various values used for
+the tests have been chosen to illustrate aspects of type
+converting, those aspects may not apply to all of the tables presented.
+However, all of the test values are included in all of the tables (except
+where no type converting occurs) for full comparison. The bodies of the
+tables list the results of the various type conversion operations.
+</p>
+
+<p id="tcInt_5">
+If you are accepting/using this page's <span class="initialism" title="Cascading Style Sheet"><abbr title="Cascading Style Sheet">CSS</abbr></span> style suggestions the type
+of the values at various stages is illustrated by the colour of the text
+used. The following key shows those type/colour relationships, they are
+derived from the string values returned by the <code>typeof</code>
+operator (which returns <code>&quot;object&quot;</code>
+for the <code>null</code> type when in reality <code>null</code> is
+distinct from objects).
+</p>
+
+<table id="tcInt_key">
+ <tbody>
+ <tr><th>Key</th></tr>
+ <tr><td class="st">string</td></tr>
+ <tr><td class="nm">number</td></tr>
+ <tr><td class="bl">boolean</td></tr>
+ <tr><td class="ob">object</td></tr>
+ <tr><td class="fn" style="text-align:center;">function</td></tr>
+ <tr><td class="ob">null</td></tr>
+ <tr><td class="un">undefined</td></tr>
+ </tbody>
+</table>
+
+<p id="tcInt_6">
+The boolean values of results also have a coloured background to highlight
+ <code>true</code> or <code>false</code>.
+</p>
+
+<h2 id="tcBool">Converting to Boolean</h2>
+
+<p id="tcBool_1">
+When evaluating the expression of an <code>if</code> statement the Javascript
+interpreter will type-convert the result of that expression to boolean
+in order to make its decision. Also various operators internally
+type-convert their operands to boolean in order to determine what
+action to take. These include the logical operators like AND
+(<code>&&</code>), OR (<code>||</code>) and NOT (<code>!</code>). The NOT
+operator type-converts its operand to boolean and if that value is
+boolean true it returns false and if false it returns true. As the
+result of a NOT operation is a boolean value that is the inverse of
+the type-converted true-ness of its operand, two NOT operations
+together will return a boolean value that is equivalent to the result
+of type-converting the operand to boolean:-
+</p>
+
+<pre id="tcBool_ex1">
+var boolValue = !!x;
+</pre>
+
+<p id="tcBool_2">
+That technique has been used to generate the following tables.
+</p>
+
+<p id="tcBool_3">
+An alternative method of generating a boolean value that represents
+the type-converted true-ness of a value is to pass that value to
+the <code>Boolean</code> constructor called as a function:-
+</p>
+
+<pre id="tcBool_ex2">
+var boolValue = Boolean(x);
+</pre>
+
+<table>
+ <caption>Double NOT (!!col) : Numeric Values.</caption>
+ <thead>
+ <tr>
+ <th></th>
+ <th class="nm">-1.6</th>
+ <th class="nm">-0</th>
+ <th class="nm">+0</th>
+ <th class="nm">1</th>
+ <th class="nm">1.6</th>
+ <th class="nm">8</th>
+ <th class="nm">16</th>
+ <th class="nm">16.8</th>
+ <th class="nm">123e-2</th>
+ <th class="nm">-Infinity</th>
+ <th class="nm">+Infinity</th>
+ <th class="nm">NaN</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <th>!!col</th>
+ <td class="true">true</td>
+ <td class="false">false</td>
+ <td class="false">false</td>
+ <td class="true">true</td>
+ <td class="true">true</td>
+ <td class="true">true</td>
+ <td class="true">true</td>
+ <td class="true">true</td>
+ <td class="true">true</td>
+ <td class="true">true</td>
+ <td class="true">true</td>
+ <td class="false">false</td>
+ </tr>
+ </tbody>
+</table>
+
+<p id="tcBool_4">
+When numbers are converted to boolean, zero becomes false and all other
+numbers are true. With the excepting of the special numeric value
+<code>NaN</code> (Not a Number) which is used when another type is
+converted to a number but that conversion does not result in a
+meaningful number. <code>NaN</code> is always false. The values of
+positive and negative infinity, while not finite numbers, are non-zero
+numeric values and always type-convert to boolean <code>true</code>.
+</p>
+
+<table>
+ <caption>Double NOT (!!col) : String Values.</caption>
+ <thead>
+ <tr>
+ <th></th>
+ <th class="st">&quot;&quot;<br>(empty<br>string)</th>
+ <th class="st">&quot;-1.6&quot;</th>
+ <th class="st">&quot;0&quot;</th>
+ <th class="st">&quot;1&quot;</th>
+ <th class="st">&quot;1.6&quot;</th>
+ <th class="st">&quot;8&quot;</th>
+ <th class="st">&quot;16&quot;</th>
+ <th class="st">&quot;16.8&quot;</th>
+ <th class="st">&quot;123e-2&quot;</th>
+ <th class="st">&quot;010&quot;<br>(Octal)</th>
+ <th class="st">&quot;0x10&quot;<br>(Hex)</th>
+ <th class="st">&quot;0xFF&quot;<br>(Hex)</th>
+ <th class="st">&quot;-010&quot;</th>
+ <th class="st">&quot;-0x10&quot;</th>
+ <th class="st">&quot;xx&quot;</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <th>!!col</th>
+ <td class="false">false</td>
+ <td class="true">true</td>
+ <td class="true">true</td>
+ <td class="true">true</td>
+ <td class="true">true</td>
+ <td class="true">true</td>
+ <td class="true">true</td>
+ <td class="true">true</td>
+ <td class="true">true</td>
+ <td class="true">true</td>
+ <td class="true">true</td>
+ <td class="true">true</td>
+ <td class="true">true</td>
+ <td class="true">true</td>
+ <td class="true">true</td>
+ </tr>
+ </tbody>
+</table>
+
+<p id="tcBool_5">
+Type conversion rules are even simpler for string to boolean conversion
+as all non-empty strings always become true and empty strings become
+false.
+</p>
+
+<table>
+ <caption>Double NOT (!!col) : Other Values</caption>
+ <thead>
+ <tr>
+ <th></th>
+ <th class="un">undefined</th>
+ <th class="ob">null</th>
+ <th class="bl">true</th>
+ <th class="bl">false</th>
+ <th class="ob">new Object()</th>
+ <th class="fn">function(){<br> return;<br>}</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <th>!!col</th>
+ <td class="false">false</td>
+ <td class="false">false</td>
+ <td class="true">true</td>
+ <td class="false">false</td>
+ <td class="true">true</td>
+ <td class="true">true</td>
+ </tr>
+ </tbody>
+</table>
+
+<p id="tcBool_6">
+For the other types, <code>undefined</code> and <code>null</code> are
+converted to false, boolean values are not converted and objects and
+functions are always true.
+</p>
+
+<p id="tcBool_7">
+This is the most valuable aspect of type-converting to boolean as it
+allows a script to distinguish between properties in an environment
+that may be undefined or may refer to an object. Treating an undefined
+(or null) value as if it was an object will produce errors. So when
+there is a doubt (as there usually is where web browsers are concerned)
+then code can avoid generating errors by wrapping the code that wants
+to access an object in an <code>if</code> test. Supplying the suspect
+reference to the object as the expression. The expression will be type
+converted to boolean and result in <code>false</code> if the object
+does not exist and <code>true</code> if it does.
+</p>
+
+<pre id="tcBool_ex3">
+if(document.documentElement){
+ scrollX = document.documentElement.scrollLeft;
+}
+</pre>
+
+<p id="tcBool_8">
+The double NOT operation also allows the setting of boolean flags that
+can be used to indicate the presence of various objects:-
+</p>
+
+<pre id="tcBool_ex4">
+var hasDocEl = !!document.documentElement;
+...
+if(hasDocEl){
+ scrollX = document.documentElement.scrollLeft;
+}
+</pre>
+
+<h2 id="tcString">Converting to String</h2>
+
+<p id="tcString_1">
+As mentioned above, type conversion to a string most often results
+from the action of the + operator whenever one of its operators in
+not a number. The easiest way of getting the string that results
+from type-conversion is to concatenate a value to an empty string.
+That technique has been used to generate the following tables.
+</p>
+
+<p id="tcString_2">
+An alternative method of converting a value into a string is to
+pass it as an argument to the <code>String</code> constructor
+called as a function:-
+</p>
+
+<pre id="tcString_ex1">
+var stringValue = String(x);
+</pre>
+
+<table>
+ <caption>type-convert to string (&quot;&quot; + col) : Numeric Values.</caption>
+ <thead>
+ <tr>
+ <th></th>
+ <th class="nm">-1.6</th>
+ <th class="nm">-0</th>
+ <th class="nm">+0</th>
+ <th class="nm">1</th>
+ <th class="nm">1.6</th>
+ <th class="nm">8</th>
+ <th class="nm">16</th>
+ <th class="nm">16.8</th>
+ <th class="nm">123e-2</th>
+ <th class="nm">-Infinity</th>
+ <th class="nm">+Infinity</th>
+ <th class="nm">NaN</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <th>&quot;&quot; + col</th>
+ <td class="st">-1.6</td>
+ <td class="st">0</td>
+ <td class="st">0</td>
+ <td class="st">1</td>
+ <td class="st">1.6</td>
+ <td class="st">8</td>
+ <td class="st">16</td>
+ <td class="st">16.8</td>
+ <td class="st">1.23</td>
+ <td class="st">-Infinity</td>
+ <td class="st">Infinity</td>
+ <td class="st">NaN</td>
+ </tr>
+ </tbody>
+</table>
+
+<p id="tcString_3">
+Notice that the number generated from the source code <code>123e-2</code>
+has resulted in the string <code>&quot;1.23&quot;</code> because that is
+the string representation of the internal number created from the source
+code. However, Javascript's internal number representations take the form
+of IEEE double precision floating point numbers and that means that they
+cannot represent all numbers with precision. The results of mathematical
+operations may only produce close approximations and when they are
+converted to strings the string represents the approximation and may be
+unexpected and undesirable. It is often necessary to use custom functions
+to generate string representations of numbers in an acceptable format,
+the type-conversion mechanism is rarely suited to generating numeric output
+intended for presentation.
+</p>
+
+<table>
+ <caption>type-convert to string (&quot;&quot; + col) : Other Values.</caption>
+ <thead>
+ <tr>
+ <th></th>
+ <th class="un">undefined</th>
+ <th class="ob">null</th>
+ <th class="bl">true</th>
+ <th class="bl">false</th>
+ <th class="ob">new Object()</th>
+ <th class="fn">function(){<br> return;<br>}</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <th>&quot;&quot; + col</th>
+ <td class="st">undefined</td>
+ <td class="st">null</td>
+ <td class="st">true</td>
+ <td class="st">false</td>
+ <td class="st">[object Object]</td>
+ <td><pre class="st">function(){
+ return;
+}</pre></td>
+ </tr>
+ </tbody>
+</table>
+
+<p id="tcString_4">
+When objects or functions are type-converted to strings their
+<code>toString</code> method is called. These default to
+<code>Object.prototype.toString</code> and
+<code>Function.prototype.toString</code> but may be overloaded
+with a function assigned to a &quot;toString&quot; property of
+the object/function. Type-converting a function to a string does
+not necessarily result in the function's source code. The behaviour
+of <code>Function.prototype.toString</code> is implementation
+depended and varies quite a lot, as do the results from
+&quot;host objects&quot; and methods (the objects and methods
+provided by the environment, such as DOM elements).
+</p>
+
+<h2 id="tcNumber">Converting to Number</h2>
+
+<p id="tcNumber_1">
+Converting values to numbers, especially strings to numbers, is an
+extremely common requirement and many methods can be used. Any
+mathematical operator except the concatenation/addition operator
+will force type-conversion. So conversion of a string to a number
+might entail performing a mathematical operation on the string
+representation of the number that would not affect the resulting
+number, such as subtracting zero or multiplying by one.
+</p>
+
+<pre id="tcNumber_ex1">
+var numValue = stringValue - 0;
+<span class="commentJS">/* or */</span>
+var numValue = stringValue * 1;
+<span class="commentJS">/* or */</span>
+var numValue = stringValue / 1;
+</pre>
+
+<p id="tcNumber_2">
+However, the unary <code>+</code> operator also type-converts its
+operand to a number and because it does not do any additional
+mathematical operations it is the fastest method for type-converting
+a string into a number.
+</p>
+
+<p id="tcNumber_2b">
+Incidentally, the unary <code>-</code> (minus) operator also
+type-converts its operand (if necessary) in addition to
+subsequently negating its value.
+</p>
+
+<pre id="tcNumber_ex2">
+var numValue = (+stringValue);
+
+<span class="commentJS">/* The preceding unary + expression has been parenthesised. That is
+ unnecessary but is often felt to make the code easier to comprehend
+ and make it clear which operations are being applied. Especially
+ avoiding confusion with pre and post increment and addition
+ operations. Compare:-
+
+var n = anyNumVar++ + +stringVar + ++anotherNumVar;
+
+ - with -
+
+var n = (anyNumVar++) + (+stringVar) + (++anotherNumVar);
+ ^^ ^ ^^
+ (post increment) + (unary plus) + (pre increment)
+*/</span>
+</pre>
+
+<p id="tcNumber_3">
+While unary <code>+</code> is the fastest method for converting a
+string to a number a final method is available that uses the
+Javascript type-conversion algorithms. The <code>Number</code>
+constructor can be called with the string value as its argument
+and its return value is a number representing the result of the
+type-conversion.
+</p>
+
+<pre id="tcNumber_ex3">
+var numValue = Number(stringValue);
+</pre>
+
+<p id="tcNumber_4">
+The Number constructor is the slowest of the type-converting
+methods but when speed is not an overriding consideration its
+use does produce the clearest source code.
+</p>
+
+<p id="tcNumber_5">
+The following tables show the results of type-conversion to a number using
+the unary <code>+</code> operator. Though all of the preceding
+alternative method produce the same results as they all use exactly the
+same algorithm to do the conversion.
+</p>
+
+<table>
+ <caption>type-convert to number (+col) : String Values.</caption>
+ <thead>
+ <tr>
+ <th></th>
+ <th class="st">&quot;&quot;<br>(empty<br>string)</th>
+ <th class="st">&quot;-1.6&quot;</th>
+ <th class="st">&quot;0&quot;</th>
+ <th class="st">&quot;1&quot;</th>
+ <th class="st">&quot;1.6&quot;</th>
+ <th class="st">&quot;8&quot;</th>
+ <th class="st">&quot;16&quot;</th>
+ <th class="st">&quot;16.8&quot;</th>
+ <th class="st">&quot;123e-2&quot;</th>
+ <th class="st">&quot;010&quot;<br>(Octal)</th>
+ <th class="st">&quot;0x10&quot;<br>(Hex)</th>
+ <th class="st">&quot;0xFF&quot;<br>(Hex)</th>
+ <th class="st">&quot;-010&quot;</th>
+ <th class="st">&quot;-0x10&quot;</th>
+ <th class="st">&quot;xx&quot;</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <th>+col</th>
+ <td class="nm">0</td>
+ <td class="nm">-1.6</td>
+ <td class="nm">0</td>
+ <td class="nm">1</td>
+ <td class="nm">1.6</td>
+ <td class="nm">8</td>
+ <td class="nm">16</td>
+ <td class="nm">16.8</td>
+ <td class="nm">1.23</td>
+ <td class="nm">10</td>
+ <td class="nm">16</td>
+ <td class="nm">255</td>
+ <td class="nm">-10</td>
+ <td class="nm">NaN</td>
+ <td class="nm">NaN</td>
+ </tr>
+ </tbody>
+</table>
+
+<p id="tcNumber_6">
+The important considerations when converting strings to numbers with
+the type-converting methods is the results from strings that do not
+represent numbers. The empty string is converted into the number zero,
+depending on the application this can be harmless or disastrous, but
+it is important to be aware that it is going to happen. In other
+contexts strings that follow the Javascript format for octal number
+(leading zero) can be problematic but type conversion treats them
+as base 10 anyway. However, strings that follow the format for
+hexadecimal numbers (leading <code>0x</code> or <code>0X</code>)
+are read as hexadecimal. Strings that cannot be read as a number
+type-convert to <code>NaN</code>, which can be tested for with
+the <code>isNaN</code> function. Strings representing numbers in an
+exponential format (<code>&quot;123e-2&quot;</code>) are understood
+along with leading minus signs.
+</p>
+
+<table>
+ <caption>type-convert to number (+col) : Other Values.</caption>
+ <thead>
+ <tr>
+ <th></th>
+ <th class="un">undefined</th>
+ <th class="ob">null</th>
+ <th class="bl">true</th>
+ <th class="bl">false</th>
+ <th class="ob">new Object()</th>
+ <th class="fn">function(){<br> return;<br>}</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <th>+col</th>
+ <td class="nm">NaN</td>
+ <td class="nm">0</td>
+ <td class="nm">1</td>
+ <td class="nm">0</td>
+ <td class="nm">NaN</td>
+ <td class="nm">NaN</td>
+ </tr>
+ </tbody>
+</table>
+
+<p id="tcNumber_7">
+Objects and functions always type-convert to <code>NaN</code> numbers, as do
+<code>undefined</code> values but it is worth noting that <code>null</code>
+type-converts to zero. Probably because it is being type-converted to boolean
+first and then to number and, as is clear from the boolean results
+above, <code>null</code> would become boolean <code>false</code> which
+would then become numeric zero. There is almost no need to type convert
+these types of values into numbers. How they convert is only really
+relevant to a consideration of the accidental result of converting a
+value that is expected to be a string but actually turns out to be one
+of these (and/or performing an mathematical operation with one of these as an operand).
+</p>
+
+<h2 id="tcParse">Parsing to Number</h2>
+
+<p id="tcParse_1">
+An alternative method of converting a string into a number is to use
+one of the global functions designed to parse a string and return a
+number. The <code>parseFloat</code> function accepts a string argument
+and returns a floating point number resulting from parsing that string.
+Non-string arguments are first type-converted to a string as described
+above.
+</p>
+
+<p id="tcParse_2">
+The string parsing functions read the string character by character until
+they encounter a character that cannot be part of the number, at which
+point they stop and return a number based on the characters that they
+have seen that can be part of the number. This feature of their action
+can be usefully exploited, for example, given a string representing a
+<span class="initialism" title="Cascading Style Sheet"><abbr title="Cascading Style Sheet">CSS</abbr></span> length value such as <code>&quot;34.5em&quot;</code>
+<code>parseFloat</code> would be able to ignore the <code>&quot;em&quot;</code>
+because those characters cannot be combined with the preceding set to
+produce a valid number. The returned number would be 34.5, the numeric
+part of the <span class="initialism" title="Cascading Style Sheet"><abbr title="Cascading Style Sheet">CSS</abbr></span> string stripped of its units.
+</p>
+
+<h3 id="tcParseFl">parseFloat</h3>
+
+<table>
+ <caption>parseFloat(col) : String Values.</caption>
+ <thead>
+ <tr>
+ <th></th>
+ <th class="st">&quot;&quot;<br>(empty<br>string)</th>
+ <th class="st">&quot;-1.6&quot;</th>
+ <th class="st">&quot;0&quot;</th>
+ <th class="st">&quot;1&quot;</th>
+ <th class="st">&quot;1.6&quot;</th>
+ <th class="st">&quot;8&quot;</th>
+ <th class="st">&quot;16&quot;</th>
+ <th class="st">&quot;16.8&quot;</th>
+ <th class="st">&quot;123e-2&quot;</th>
+ <th class="st">&quot;010&quot;<br>(Octal)</th>
+ <th class="st">&quot;0x10&quot;<br>(Hex)</th>
+ <th class="st">&quot;0xFF&quot;<br>(Hex)</th>
+ <th class="st">&quot;-010&quot;</th>
+ <th class="st">&quot;-0x10&quot;</th>
+ <th class="st">&quot;xx&quot;</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <th>parseFloat(col)</th>
+ <td class="nm">NaN</td>
+ <td class="nm">-1.6</td>
+ <td class="nm">0</td>
+ <td class="nm">1</td>
+ <td class="nm">1.6</td>
+ <td class="nm">8</td>
+ <td class="nm">16</td>
+ <td class="nm">16.8</td>
+ <td class="nm">1.23</td>
+ <td class="nm">10</td>
+ <td class="nm">0</td>
+ <td class="nm">0</td>
+ <td class="nm">-10</td>
+ <td class="nm">0</td>
+ <td class="nm">NaN</td>
+ </tr>
+ </tbody>
+</table>
+
+<p id="tcParseFl_1">
+With <code>parseFloat</code> empty strings return <code>NaN </code>
+along with strings that cannot be subject to numeric interpretation.
+The exponential format is understood and the leading zero in the
+octal format does not hinder the string's interpretation as a
+decimal number. Hexadecimal strings are interpreted as the number
+zero because the following <code>&quot;x&quot;</code> cannot be
+interpreted as part of a number so parsing stops after the leading zero.
+</p>
+
+<table>
+ <caption>parseFloat(col) : Other Values.</caption>
+ <thead>
+ <tr>
+ <th></th>
+ <th class="un">undefined</th>
+ <th class="ob">null</th>
+ <th class="bl">true</th>
+ <th class="bl">false</th>
+ <th class="ob">new Object()</th>
+ <th class="fn">function(){<br> return;<br>}</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <th>parseFloat(col)</th>
+ <td class="nm">NaN</td>
+ <td class="nm">NaN</td>
+ <td class="nm">NaN</td>
+ <td class="nm">NaN</td>
+ <td class="nm">NaN</td>
+ <td class="nm">NaN</td>
+ </tr>
+ </tbody>
+</table>
+
+<p id="tcParseFl_2">
+Non-string values are first converted into a string that is employed
+by <code>parseFloat</code>. As that type-conversion to a string would
+not normally result in a string that could be interpreted as a number
+the result is <code>NaN</code>. Objects and functions may have custom
+<code>toString</code> methods that may return strings that could be
+interpreted as numbers but that would be an unusual requirement.
+</p>
+
+<h3 id="tcParseIn">parseInt</h3>
+
+<p id="tcParseIn_1">
+The <code>parseInt</code> function works in a similar way to
+<code>parseFloat</code> except that it is trying to interpret its
+string argument into an integer and as a result recognises fewer
+character as possible candidates to be part of that number.
+</p>
+
+<p id="tcParseIn_2">
+<code>parseInt</code> is occasionally used as a means of turning a
+floating point number into an integer. It is very ill suited to that
+task because if its argument is of numeric type it will first be
+converted into a string and then parsed as a number, very inefficient.
+This can produce very wrong results with numbers such as
+<code>2e-200</code>, for which the next smaller integer is zero, but
+with which <code>parseInt</code> returns <code>2</code>. Also, because
+of the number format used by javascript, numbers are often represented
+by near approximations. So, for example, 1/2 + 1/3 + 1/6 =
+0.9999999999999999, which isn't quite one and parseInt would return
+zero if asked to act on the result of the operation.
+</p>
+
+<p id="tcParseIn_3">
+For rounding
+numbers to integers one of <code>Math.round</code>, <code>Math.ceil</code>
+and <code>Math.floor</code> are preferable, and for a desired result
+that can be expressed as a 32 bit signed integer the bitwise operation
+described below might also suit.
+</p>
+
+<table>
+ <caption>parseInt(col) : Numeric Values.</caption>
+ <thead>
+ <tr>
+ <th></th>
+ <th class="nm">-1.6</th>
+ <th class="nm">-0</th>
+ <th class="nm">+0</th>
+ <th class="nm">1</th>
+ <th class="nm">1.6</th>
+ <th class="nm">8</th>
+ <th class="nm">16</th>
+ <th class="nm">16.8</th>
+ <th class="nm">123e-2</th>
+ <th class="nm">-Infinity</th>
+ <th class="nm">+Infinity</th>
+ <th class="nm">NaN</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <th>parseInt(col)</th>
+ <td class="nm">-1</td>
+ <td class="nm">0</td>
+ <td class="nm">0</td>
+ <td class="nm">1</td>
+ <td class="nm">1</td>
+ <td class="nm">8</td>
+ <td class="nm">16</td>
+ <td class="nm">16</td>
+ <td class="nm">1</td>
+ <td class="nm">NaN</td>
+ <td class="nm">NaN</td>
+ <td class="nm">NaN</td>
+ </tr>
+ </tbody>
+</table>
+
+<p id="tcParseIn_4">
+When it is acting on number the effect of the initial type-conversion
+of the argument to a string is evident in the results. Note that the
+value <code>123e-2</code> is internally the number <code>1.23</code>
+and that type converts into the string <code>&quot;1.23&quot;</code>,
+so that entry in the table above might look odd but it is correct.
+</p>
+
+<table>
+ <caption>parseInt(col) : String Values.</caption>
+ <thead>
+ <tr>
+ <th></th>
+ <th class="st">&quot;&quot;<br>(empty<br>string)</th>
+ <th class="st">&quot;-1.6&quot;</th>
+ <th class="st">&quot;0&quot;</th>
+ <th class="st">&quot;1&quot;</th>
+ <th class="st">&quot;1.6&quot;</th>
+ <th class="st">&quot;8&quot;</th>
+ <th class="st">&quot;16&quot;</th>
+ <th class="st">&quot;16.8&quot;</th>
+ <th class="st">&quot;123e-2&quot;</th>
+ <th class="st">&quot;010&quot;<br>(Octal)</th>
+ <th class="st">&quot;0x10&quot;<br>(Hex)</th>
+ <th class="st">&quot;0xFF&quot;<br>(Hex)</th>
+ <th class="st">&quot;-010&quot;</th>
+ <th class="st">&quot;-0x10&quot;</th>
+ <th class="st">&quot;xx&quot;</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <th>parseInt(col)</th>
+ <td class="nm">NaN</td>
+ <td class="nm">-1</td>
+ <td class="nm">0</td>
+ <td class="nm">1</td>
+ <td class="nm">1</td>
+ <td class="nm">8</td>
+ <td class="nm">16</td>
+ <td class="nm">16</td>
+ <td class="nm">123</td>
+ <td class="nm">8</td>
+ <td class="nm">16</td>
+ <td class="nm">255</td>
+ <td class="nm">-8</td>
+ <td class="nm">-16</td>
+ <td class="nm">NaN</td>
+ </tr>
+ </tbody>
+</table>
+
+<p id="tcParseIn_5">
+Strings in octal and hexadecimal number formats do represent integers
+and <code>parseInt</code> is capable of interpreting them in accordance
+with the rules for Javascript source code, even when they have leading
+minus signs.
+</p>
+
+<table>
+ <caption>parseInt(col) : Other Values.</caption>
+ <thead>
+ <tr>
+ <th></th>
+ <th class="un">undefined</th>
+ <th class="ob">null</th>
+ <th class="bl">true</th>
+ <th class="bl">false</th>
+ <th class="ob">new Object()</th>
+ <th class="fn">function(){<br> return;<br>}</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <th>parseInt(col)</th>
+ <td class="nm">NaN</td>
+ <td class="nm">NaN</td>
+ <td class="nm">NaN</td>
+ <td class="nm">NaN</td>
+ <td class="nm">NaN</td>
+ <td class="nm">NaN</td>
+ </tr>
+ </tbody>
+</table>
+
+<p id="tcParseIn_6">
+As <code>parseInt</code> type-converts its non-string arguments to
+strings it always produces the same results for <code>boolean</code>,
+<code>null</code>, <code>undefined</code>, object and function
+arguments as <code>parseFloat</code> (assuming objects and functions
+do not have custom <code>toString</code> methods).
+</p>
+
+<h3 id="tcPrIntRx">parseInt with a radix argument</h3>
+
+<p id="tcPrIntRx_1">
+It is rarely desirable to allow <code>parseInt</code> to deduce the
+base in which the number is represented from the string as leading zeros are
+rarely intended to indicate data in octal format (particularly with
+user input). To deal with this problem <code>parseInt</code> recognises
+a second, radix, argument that can be used to specify the base in which the
+string is to be interpreted. Specifying a second argument of 10 causes
+<code>parseInt</code> to interpret the strings as only base 10.
+</p>
+
+<table>
+ <caption>parseInt(col, 10) : String Values.</caption>
+ <thead>
+ <tr>
+ <th></th>
+ <th class="st">&quot;&quot;<br>(empty<br>string)</th>
+ <th class="st">&quot;-1.6&quot;</th>
+ <th class="st">&quot;0&quot;</th>
+ <th class="st">&quot;1&quot;</th>
+ <th class="st">&quot;1.6&quot;</th>
+ <th class="st">&quot;8&quot;</th>
+ <th class="st">&quot;16&quot;</th>
+ <th class="st">&quot;16.8&quot;</th>
+ <th class="st">&quot;123e-2&quot;</th>
+ <th class="st">&quot;010&quot;<br>(Octal)</th>
+ <th class="st">&quot;0x10&quot;<br>(Hex)</th>
+ <th class="st">&quot;0xFF&quot;<br>(Hex)</th>
+ <th class="st">&quot;-010&quot;</th>
+ <th class="st">&quot;-0x10&quot;</th>
+ <th class="st">&quot;xx&quot;</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <th>parseInt(col, 10)</th>
+ <td class="nm">NaN</td>
+ <td class="nm">-1</td>
+ <td class="nm">0</td>
+ <td class="nm">1</td>
+ <td class="nm">1</td>
+ <td class="nm">8</td>
+ <td class="nm">16</td>
+ <td class="nm">16</td>
+ <td class="nm">123</td>
+ <td class="nm">10</td>
+ <td class="nm">0</td>
+ <td class="nm">0</td>
+ <td class="nm">-10</td>
+ <td class="nm">0</td>
+ <td class="nm">NaN</td>
+ </tr>
+ </tbody>
+</table>
+
+<p id="tcPrIntRx_2">
+The string in octal format is now interpreted as base 10 and the
+hexadecimal strings can now only be zero as parsing has to stop
+when the <code>&quot;x&quot;</code> is encountered.
+</p>
+
+<p id="tcPrIntRx_3">
+Number bases 2 to 36 can be used with <code>parseInt</code>. The
+following is base 16.
+</p>
+
+<table>
+ <caption>parseInt(col, 16) : String Values.</caption>
+ <thead>
+ <tr>
+ <th></th>
+ <th class="st">&quot;&quot;<br>(empty<br>string)</th>
+ <th class="st">&quot;-1.6&quot;</th>
+ <th class="st">&quot;0&quot;</th>
+ <th class="st">&quot;1&quot;</th>
+ <th class="st">&quot;1.6&quot;</th>
+ <th class="st">&quot;8&quot;</th>
+ <th class="st">&quot;16&quot;</th>
+ <th class="st">&quot;16.8&quot;</th>
+ <th class="st">&quot;123e-2&quot;</th>
+ <th class="st">&quot;010&quot;<br>(Octal)</th>
+ <th class="st">&quot;0x10&quot;<br>(Hex)</th>
+ <th class="st">&quot;0xFF&quot;<br>(Hex)</th>
+ <th class="st">&quot;-010&quot;</th>
+ <th class="st">&quot;-0x10&quot;</th>
+ <th class="st">&quot;xx&quot;</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <th>parseInt(col, 16)</th>
+ <td class="nm">NaN</td>
+ <td class="nm">-1</td>
+ <td class="nm">0</td>
+ <td class="nm">1</td>
+ <td class="nm">1</td>
+ <td class="nm">8</td>
+ <td class="nm">22</td>
+ <td class="nm">22</td>
+ <td class="nm">4670</td>
+ <td class="nm">16</td>
+ <td class="nm">16</td>
+ <td class="nm">255</td>
+ <td class="nm">-16</td>
+ <td class="nm">-16</td>
+ <td class="nm">NaN</td>
+ </tr>
+ </tbody>
+</table>
+
+<p id="tcPrIntRx_4">
+The hexadecimal <code>0x</code> format is recognised again with the
+base 16 interpretation.
+</p>
+
+<p id="tcPrIntRx_5">
+Finally base 3:-
+</p>
+
+<table>
+ <caption>parseInt(col, 3) : Numeric Values.</caption>
+ <thead>
+ <tr>
+ <th></th>
+ <th class="nm">-1.6</th>
+ <th class="nm">-0</th>
+ <th class="nm">+0</th>
+ <th class="nm">1</th>
+ <th class="nm">1.6</th>
+ <th class="nm">8</th>
+ <th class="nm">16</th>
+ <th class="nm">16.8</th>
+ <th class="nm">123e-2</th>
+ <th class="nm">-Infinity</th>
+ <th class="nm">+Infinity</th>
+ <th class="nm">NaN</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <th>parseInt(col, 3)</th>
+ <td class="nm">-1</td>
+ <td class="nm">0</td>
+ <td class="nm">0</td>
+ <td class="nm">1</td>
+ <td class="nm">1</td>
+ <td class="nm">NaN</td>
+ <td class="nm">1</td>
+ <td class="nm">1</td>
+ <td class="nm">1</td>
+ <td class="nm">NaN</td>
+ <td class="nm">NaN</td>
+ <td class="nm">NaN</td>
+ </tr>
+ </tbody>
+</table>
+
+<p id="tcPrIntRx_6">
+The consequences of the type-converting of numeric arguments to
+strings is evident again. The number <code>8</code> is coming out
+as <code>NaN</code> because the <code>&quot;8&quot;</code> character
+cannot be interpreted as base 3, leaving an empty sequence of
+acceptable characters and producing the same result as an empty string.
+</p>
+
+<table>
+ <caption>parseInt(col, 3) : String Values.</caption>
+ <thead>
+ <tr>
+ <th></th>
+ <th class="st">&quot;&quot;<br>(empty<br>string)</th>
+ <th class="st">&quot;-1.6&quot;</th>
+ <th class="st">&quot;0&quot;</th>
+ <th class="st">&quot;1&quot;</th>
+ <th class="st">&quot;1.6&quot;</th>
+ <th class="st">&quot;8&quot;</th>
+ <th class="st">&quot;16&quot;</th>
+ <th class="st">&quot;16.8&quot;</th>
+ <th class="st">&quot;123e-2&quot;</th>
+ <th class="st">&quot;010&quot;<br>(Octal)</th>
+ <th class="st">&quot;0x10&quot;<br>(Hex)</th>
+ <th class="st">&quot;0xFF&quot;<br>(Hex)</th>
+ <th class="st">&quot;-010&quot;</th>
+ <th class="st">&quot;-0x10&quot;</th>
+ <th class="st">&quot;xx&quot;</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <th>parseInt(col, 3)</th>
+ <td class="nm">NaN</td>
+ <td class="nm">-1</td>
+ <td class="nm">0</td>
+ <td class="nm">1</td>
+ <td class="nm">1</td>
+ <td class="nm">NaN</td>
+ <td class="nm">1</td>
+ <td class="nm">1</td>
+ <td class="nm">5</td>
+ <td class="nm">3</td>
+ <td class="nm">0</td>
+ <td class="nm">0</td>
+ <td class="nm">-3</td>
+ <td class="nm">0</td>
+ <td class="nm">NaN</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="tcToInt32">ToInt32</h2>
+
+<p id="tcToInt32_1">
+<code>ToInt32</code> is an <em>internal</em> function only available to the
+Javascript implementation and cannot be called directly from scripts
+in the way that <code>parseInt</code> can. It is a bit unusual to mention it in
+connection with converting Javascript values to numbers but it can
+be used in a limited set of circumstances. The bitwise operators such
+as bitwise OR (<code>|</code>) and bitwise AND (<code>&</code>) operate on
+numbers so they type-convert their operands to numbers. However, they
+also only operate on 32 bit signed integers so given the (possibly
+type-converted) numeric value they call the <em>internal</em>
+<code>ToInt32</code> function with that number as its argument and
+use the returned value as their operand. That returned value is always
+a 32 bit signed integer.
+</p>
+
+<p id="tcToInt32_2">
+The effect can be like <code>parseInt</code> combined with type-converting
+to numbers. While the result is limited in range to 32 bits, it is
+<em>always</em> numeric and never <code>NaN</code>, or &plusmn;
+<code>Infinity</code>.
+</p>
+
+<p id="tcToInt32_3">
+As with using mathematical operators in operations that have no effect on
+the value of any resulting number it is possible to perform a bitwise
+operation that will not affect the value returned from the call to
+<code>ToInt32</code>. The tables below were generated using a bitwise
+OR zero operation.
+</p>
+
+<table>
+ <caption> ToInt32 (col|0) : Numeric Values.</caption>
+ <thead>
+ <tr>
+ <th></th>
+ <th class="nm">-1.6</th>
+ <th class="nm">-0</th>
+ <th class="nm">+0</th>
+ <th class="nm">1</th>
+ <th class="nm">1.6</th>
+ <th class="nm">8</th>
+ <th class="nm">16</th>
+ <th class="nm">16.8</th>
+ <th class="nm">123e-2</th>
+ <th class="nm">-Infinity</th>
+ <th class="nm">+Infinity</th>
+ <th class="nm">NaN</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <th>col|0</th>
+ <td class="nm">-1</td>
+ <td class="nm">0</td>
+ <td class="nm">0</td>
+ <td class="nm">1</td>
+ <td class="nm">1</td>
+ <td class="nm">8</td>
+ <td class="nm">16</td>
+ <td class="nm">16</td>
+ <td class="nm">1</td>
+ <td class="nm">0</td>
+ <td class="nm">0</td>
+ <td class="nm">0</td>
+ </tr>
+ </tbody>
+</table>
+
+<p id="tcToInt32_4">
+<code>NaN</code> and &plusmn;<code>Infinity</code> become zero and
+floating point values are <em>truncated</em> to integers.
+</p>
+
+<table>
+ <caption> ToInt32 (col|0) : String Values.</caption>
+ <thead>
+ <tr>
+ <th></th>
+ <th class="st">&quot;&quot;<br>(empty<br>string)</th>
+ <th class="st">&quot;-1.6&quot;</th>
+ <th class="st">&quot;0&quot;</th>
+ <th class="st">&quot;1&quot;</th>
+ <th class="st">&quot;1.6&quot;</th>
+ <th class="st">&quot;8&quot;</th>
+ <th class="st">&quot;16&quot;</th>
+ <th class="st">&quot;16.8&quot;</th>
+ <th class="st">&quot;123e-2&quot;</th>
+ <th class="st">&quot;010&quot;<br>(Octal)</th>
+ <th class="st">&quot;0x10&quot;<br>(Hex)</th>
+ <th class="st">&quot;0xFF&quot;<br>(Hex)</th>
+ <th class="st">&quot;-010&quot;</th>
+ <th class="st">&quot;-0x10&quot;</th>
+ <th class="st">&quot;xx&quot;</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <th>col|0</th>
+ <td class="nm">0</td>
+ <td class="nm">-1</td>
+ <td class="nm">0</td>
+ <td class="nm">1</td>
+ <td class="nm">1</td>
+ <td class="nm">8</td>
+ <td class="nm">16</td>
+ <td class="nm">16</td>
+ <td class="nm">1</td>
+ <td class="nm">10</td>
+ <td class="nm">16</td>
+ <td class="nm">255</td>
+ <td class="nm">-10</td>
+ <td class="nm">0</td>
+ <td class="nm">0</td>
+ </tr>
+ </tbody>
+</table>
+
+<p id="tcToInt32_5">
+String values that would type-convert to <code>NaN</code> are returned
+as zero from <code>ToInt32</code>.
+</p>
+
+<table>
+ <caption> ToInt32 (col|0) : Other Values.</caption>
+ <thead>
+ <tr>
+ <th></th>
+ <th class="un">undefined</th>
+ <th class="ob">null</th>
+ <th class="bl">true</th>
+ <th class="bl">false</th>
+ <th class="ob">new Object()</th>
+ <th class="fn">function(){<br> return;<br>}</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <th>col|0</th>
+ <td class="nm">0</td>
+ <td class="nm">0</td>
+ <td class="nm">1</td>
+ <td class="nm">0</td>
+ <td class="nm">0</td>
+ <td class="nm">0</td>
+ </tr>
+ </tbody>
+</table>
+
+<p id="tcToInt32_6">
+Even <code>undefined</code>, objects and functions are converted to zero value
+numbers by this operation. Note though that boolean <code>true</code> is
+converted to the number 1.
+</p>
+
+
+<h2 id="tcUserIn">Converting User Input</h2>
+
+<p id="tcUserIn_1">
+Most of the mechanisms for getting input from the user,
+<code>&lt;input type=&quot;text&quot;&gt;</code> and
+<code>prompt</code> for example, provide their results in the form
+of strings. If the user is expected to input a number they still
+might enter anything (at the least they may just make a typo). If
+the string needs to be converted into a number for later operations
+one of the methods mentioned above can be chosen based on what best
+suits the nature of the input expected but some of the results
+generated with erroneous input may be difficult to detect and handle.
+</p>
+
+<p id="tcUserIn_2">
+Prior to converting a string to a number it may be advantageous
+to use a Regular Expression to test the contents of the string
+to ensure that they conform to an acceptable format. That would
+serve to eliminate some of the string values that may otherwise
+suffer from the quirks of the string to number converting
+processes when applied to unexpected string values.
+</p>
+
+
+<h3 id="tcRegEx">Regular expression examples</h3>
+
+<pre id="tcRegExEm">
+/^\d+$/ <span class="commentJS">//All-digit</span>
+/^\s*[-+]?\d+\s*$/ <span class="commentJS">//Unbroken Signed integer &amp; spaces</span>
+/^\d{1,5}$/ <span class="commentJS">//1 to 5 digits</span>
+/^\d+\.\d\d$/ <span class="commentJS">//Money</span>
+/^\d+(\.\d{2})$/ <span class="commentJS">//Money</span>
+/^\d{1,3}(,\d\d\d)*\.\d\d$/ <span class="commentJS">//comma-separated money - 12,432.57</span>
+
+ <span class="commentJS">// optional comma-separated money - 12,432.57 or 12432.57</span>
+/^\d{1,3}(,\d\d\d)*\.\d\d$|^\d+\.\d\d$/
+
+</pre>
+</body>
+</html>
/trunk/cljs/faq_notes/type_convert.html
Property changes:
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: trunk/cljs/faq_notes/form_access.html
===================================================================
--- trunk/cljs/faq_notes/form_access.html (nonexistent)
+++ trunk/cljs/faq_notes/form_access.html (revision 43)
@@ -0,0 +1,729 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html lang="en">
+<head><title>Referencing Forms and Form Controls</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<link href="../../faq.css" rel="stylesheet" type="text/css">
+<link href="../notes.css" rel="stylesheet" type="text/css">
+<style type="text/css">
+.commentJS {
+ background-color: #FFFFCC;
+ color: #004800;
+}
+P CODE {
+ background-color: #FFFFDD;
+ color: #000000;
+ padding: 0ex;
+ margin: 0ex;
+}
+</style>
+</head>
+<body>
+
+<h1 id="faHead">Referencing Forms and Form Controls</h1>
+<div id="faqNav">
+ <a href="../../">FAQ</a> &gt; <a href="../">FAQ Notes</a>
+</div>
+
+<ul>
+ <li><a href="#faInt">Introduction</a>
+ <ul>
+ <li><a href="#faInF">Forms</a></li>
+ <li><a href="#faInC">Form Controls</a></li>
+ </ul>
+ </li>
+ <li><a href="#faShrt">Shortcut Accessors</a></li>
+ <li><a href="#faComMis">The Most Common Mistake</a></li>
+ <li><a href="#faAnon">Anonymous Form References</a></li>
+ <li><a href="#faBut">Radio Button and Other Control Collections</a></li>
+ <li><a href="#faEff">Efficient use of Form Accessors</a></li>
+</ul>
+
+<h2 id="faInt">Introduction</h2>
+<h3 id="faInF">Forms</h3>
+<p id="faInF_1">
+When the W3C defined the <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> DOM specification much of what they included
+represented a formalisation of existing browser behaviour. In particular they
+defined &quot;convenience&quot; properties on the <code>HTMLDocument</code>
+interface that reproduce document level collections common in preceding
+browsers. Of specific interest here is the <code>document.forms</code>
+collection, which makes all of the <code>FORM</code> elements on a page
+available as (zero based) indexed members of the collection. Allowing,
+for example, the second <code>FORM</code> element on a page to be
+referenced as:-
+</p>
+
+<pre id="faInF_ex1">
+var formElement = document.forms[1];
+</pre>
+
+<p id="faInF_2">
+<span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> (but not necessarily XHTML) <code>FORM</code> elements are allowed
+<code>NAME</code> attributes and the <code>document.forms</code> collection
+also makes <code>FORM</code> elements with <code>NAME</code> attributes
+available as named members, under a property name that corresponds with
+value of the <code>NAME</code> attribute. So given a form with the
+attribute <code>name=&quot;myForm&quot;</code> the form can be referenced
+as:-
+</p>
+
+<pre id="faInF_ex2">
+var formElement = document.forms.myForm;
+
+<span class="commentJS">/* - or - */</span>
+
+var formElement = document.forms[&quot;myForm&quot;];
+
+<span class="commentJS">/* The latter, bracket notation, does not impose the same restrictions
+ on the character sequence used for the name as is imposed by the
+ preceding dot notation, which is restricted to only using character
+ sequences that would fulfill the ECMAScript definition of an
+ identifier.
+
+ Bracket notation is often preferred when accessing form elements as
+ it helps to document itself by making it clear in the source code
+ which property names originate in the <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> rather than the DOM.
+*/</span>
+</pre>
+
+<p id="faInF_3">
+The <code>document.forms</code> collection had exhibited this behaviour
+in all of the preceding browsers that implemented it (which included
+all the browsers that understood what a form was) and as a result
+represents the most cross-browser method of accessing <code>FORM</code>
+elements. It is both W3C <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> DOM standard compliant and
+back-compatible with pre-existing browsers.
+</p>
+
+<p id="faInF_4">
+The W3C went on to require <code>FORM</code> elements with
+<code>ID</code> attributes to also be made available as named properties
+of the <code>document.forms</code> collection. That represented a
+formalisation of behaviour already exhibited in IE 4 but not by
+Netscape 4 (and earlier). Referencing <code>ID</code>ed <code>FORM</code>
+elements as named properties of the <code>document.forms</code> collection
+should work reliably in all W3C <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> DOM compliant browsers but some
+back-compatibility will be sacrificed if <code>ID</code>s are used instead
+of <code>NAME</code>s (though not nearly as much as would be lost if
+<code>ID</code>ed form elements were referenced using the
+<code>document.getElementById</code> method).
+</p>
+
+<p id="faInF_5">
+When writing <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> that conforms to a DTD that allows <code>FORM</code>
+elements to have <code>NAME</code> attributes it is possible to also give
+the <code>FORM</code> element an <code>ID</code> attribute that corresponds
+with its <code>NAME</code> attribute (so long as the <code>ID</code> is
+unique on the page). The form will appear as a member of the
+<code>document.forms</code> collection under a property name that
+corresponds with the value of the <code>NAME</code> and <code>ID</code>
+attributes (as they are identical).
+</p>
+
+<h3 id="faInC">Form Controls</h3>
+
+<p id="faInC_1">
+Traditionally browsers that implemented the <code>document.forms</code>
+collection also made the controls within a form available as a
+collection accessible as a property of the <code>FORM</code> element
+under the name <code>elements</code>. The W3C <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> DOM also formalised
+this collection in the <code>HTMLFormElement</code> interface.
+Controls within a form can be referenced as integer indexed members of
+that collection:-
+</p>
+
+<pre id="faInC_ex1">
+var formElement = document.forms[&quot;myForm&quot;];
+var controlElement = formElement.elements[2]; <span class="commentJS">//Third control in the form.</span>
+</pre>
+
+<p id="faInC_2">
+Controlls with <code>NAME</code> attributes are again made available as
+named properties of the collection. So a control with
+<code>name=&quot;myControl&quot;</code> can be referenced as:-
+</p>
+
+<pre id="faInC_ex2">
+var controlElement = formElement.elements[&quot;myControl&quot;];
+</pre>
+
+<p id="faInC_3">
+Again the W3C also specified that controls with <code>ID</code>
+attributes should be made available as named members of the
+elements collection under their <code>ID</code>s (with the same
+implications for back-compatibility with really ancient browsers).
+All official (x)<span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> DTDs allow form controls to have
+<code>NAME</code> attributes because without a <code>NAME</code>
+attribute the value of the control cannot be sent as a
+name/value pair when the form is submitted.
+</p>
+
+<h2 id="faShrt">Shortcut Accessors</h2>
+
+<p id="faShrt_1">
+In addition to making named <code>FORM</code> elements available
+as named properties of the <code>document.forms</code> collection
+web browsers also make them available as named properties of the
+<code>document</code> object. So:-
+</p>
+
+<pre id="faShrt_ex1">
+var formElement = document.myForm;
+</pre>
+
+<p id="faShrt_2">
+-will reference the same FORM element as:-
+</p>
+
+<pre id="faShrt_ex2">
+var formElement = document.forms.myForm;
+</pre>
+
+<p id="faShrt_3">
+And the same is true using bracket notation:-
+</p>
+
+<pre id="faShrt_ex3">
+var formElement = document[&quot;myForm&quot;];
+
+<span class="commentJS">/* instead of:- */ </span>
+
+var formElement = document.forms[&quot;myForm&quot;];
+</pre>
+
+<p id="faShrt_4">
+The W3C did not include this shortcut in the <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> DOM specifications
+so code that uses it cannot be described as standards compliant and,
+while nobody has been able to name an <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> browser where the shortcut
+accessors do not work when referencing named <code>FORM</code>
+elements, it would still be possible for a future standards compliant
+browser not to support the shortcut accessors.
+</p>
+
+<p id="faShrt_5">
+<code>FORM</code> elements that only have <code>ID</code> attributes
+cannot be accessed as properties of the <code>document</code> object
+under a property name that corresponds with their <code>ID</code>
+attributes. While by W3C <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> DOM specification (but not necessarily
+on older browsers) <code>ID</code>ed forms are made available as named
+properties of the <code>document.forms</code> collections under a
+property name that corresponds with the <code>ID</code>.
+</p>
+
+<p id="faShrt_6">
+Form controls can be referenced as named properties of the
+<code>FORM</code> element that contains them with a shortcut accessor:-
+</p>
+
+<pre id="faShrt_ex4">
+var formControl = formElement.myControl;
+
+<span class="commentJS">/* instead of :- */</span>
+
+var formControl = fromElement.elements.myControl;
+</pre>
+
+<p id="faShrt_7">
+But in the case of form controls, elements with <code>ID</code>
+attributes may be available as properties of the <code>FORM</code>
+element under a property name that corresponds with their
+<code>ID</code> (at least on more recent browsers).
+</p>
+
+<p id="faShrt_8">
+The main argument in favour of using shortcut accessors (apart from the
+reduced amount of typing) is that they are resolved fractionally quicker
+than accessors that employ the <code>forms</code> and
+<code>elements</code> collections. That follows from the fact that fewer
+object references need to be resolved before the reference to the element
+of interest is returned.
+</p>
+
+<p id="faShrt_9">
+While arguments against the shortcut accessors point out that named image,
+embed and other elements are also made available as named properties of
+the <code>document</code> object, making it ambiguous when reading the
+source code whether the shortcut accessor is referring to a form or some
+other named property of the <code>document</code> object. When a
+<code>FORM</code> element is referenced as a member of the
+<code>document.forms</code> collection, or a control as a member of the
+<code>elements</code> collection, there can be no doubt while reading
+the source code as to the type of element that is the subject of the
+reference.
+</p>
+
+<h2 id="faComMis">The Most Common Mistake</h2>
+
+<p id="faComMis_1">
+The most common mistake made when defining the form <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> that a script
+will interact with follows from the existence of the shortcut accessors
+for form controls. It is to give the control a <code>NAME</code> (or
+possibly <code>ID</code>) that corresponds with an existing property of
+<code>FORM</code> elements. And the most common example of that is an
+<code>INPUT</code> element of <code>type=&quot;submit&quot;</code> with
+the <code>NAME</code> &quot;submit&quot;. Because the named controls are
+made available as named properties of the <code>FORM</code> element this
+<code>INPUT</code> element is made available under the property name
+<code>&quot;submit&quot;</code>. Unfortunately <code>FORM</code> elements
+already have a property with the name <code>&quot;submit&quot;</code>, it
+is the <code>submit</code> method that can be used to submit the form
+with a script. The misguided choice of name for the <code>INPUT</code>
+element effectively renders the form's <code>submit</code> method
+unscriptable. And the same is true for all controls with names that
+correspond any with existing <code>FORM</code> element properties.
+</p>
+
+<p id="faComMis_2">
+Because ECMAScript is case sensitive it may only be necessary to
+capitalise the name of the <code>INPUT</code> element to avoid the
+conflict. However, it would probably be safest to adopt a naming
+convention for form controls that ensured that they do not
+correspond with existing properties of the <code>FORM</code> elements
+regardless of case. Especially as theW3C <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> specification implies
+that referring to named properties of collections can be case
+insensitive in <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> DOMs. In reality I don't know of any
+implementations in which it is but it would be better to err on the side
+of caution.
+</p>
+
+<p id="faComMis_3">
+Another naming conflict that should be avoided would arise if named form
+controls had names that correspond with the string representations of
+integers, such as <code>name=&quot;1&quot;</code> as they will almost
+certainly result in inconsistent results (across browsers) when being
+referenced because the controls are already available by integer index
+and it would become unclear which control was being referenced by
+accessors such as <code>formElement.elements[1]</code> or
+<code>formElement.elements[&quot;1&quot;]</code> (by the ECMAScript
+specification the preceding two property accessors are equivalent).
+Unless the control with the name <code>&quot;1&quot;</code> also
+happened to be the control with the index 1. This problem would also
+apply to <code>FORM</code> elements within the <code>document.forms</code>
+collection.
+</p>
+
+<p id="faComMis_4">
+Generally it is best to only give form controls names that cannot
+conflict with existing properties of <code>FORM</code> elements
+and <code>FORM</code> elements names that cannot conflict with
+existing properties of the <code>document.forms</code> collection
+or the <code>document</code> object.
+</p>
+
+<h2 id="faAnon">Anonymous Form References</h2>
+
+<p id="faAnon_1">
+Because <code>FORM</code> elements are available as integer indexed
+member of the <code>document.forms</code> collection it is not
+necessary to know the name of a form (or for the form to have a
+name) to acquire a reference to it. While being able to refer to a
+form anonymously with its index might seem like a good approach
+towards making more general/flexible functions for form validation
+and the like, in practice referring to forms by their index actually
+makes code less flexible and harder to maintain. As soon as the
+number or layout of forms on a page is changed their indexes also
+change, requiring that all of the references by index be located
+and altered.
+</p>
+
+<p id="faAnon_2">
+One method of avoiding having to know the name of a <code>FORM</code>
+element within a function that is to act upon a form is to pass a
+reference to the form object as an argument in the function call.
+This is easiest achieved from the code provided as the value for
+an event handling attribute because that code is used by the browser
+to create an event handling function that is assigned as a method of
+the element to which it is attached. And in any function executed as
+a method of an object the <code>this</code> keyword is a reference to
+the object with which the execution of the method is associated. The
+most common need to anonymously pass a reference to a <code>FORM</code>
+element is as an argument to a form validation function in the
+onsubmit handler of the form. In that case the event handling function
+is a method of the <code>FORM</code> element so the <code>this</code>
+keyword refers to the form directly:-
+</p>
+
+<pre id="faAnon_ex1">
+function validateForm(formRef){
+ <span class="commentJS">/* Use the reference to the form passed as the formal
+ parameter - formRef - to acquire a reference to the form
+ control with the name &quot;textField&quot;:
+ */</span>
+ var el = formRef &amp;&amp; formRef.elements[&quot;textField&quot;];
+ <span class="commentJS">/* If the control reference exists return its value property
+ converted to a boolean value (false if empty, true otherwise)
+ else return true so the form is submitted and the server can
+ do the validation:
+ */</span>
+ return !el || Boolean(el.value);
+}
+...
+&lt;form action=&quot;http://example.com/somePage.asp&quot;
+ onsubmit=&quot;return validateForm(this);&quot;&gt;
+ &lt;input type=&quot;text&quot; name=&quot;textField&quot; value=&quot;&quot;&gt;
+ &lt;input type=&quot;submit&quot; name=&quot;Submit_Button&quot; value=&quot;Submit&quot;&gt;
+&lt;/form&gt;
+</pre>
+
+<p id="faAnon_3">
+Because the above function receives the reference to the form that it
+is to validate as an argument when it is called it can also be used
+with any number of other forms. Although in the case of the above
+function each of those forms would need to contain a field called
+<code>&quot;textField&quot;</code>, but that string name could also be
+passed as an argument, making the function more general.
+</p>
+
+<p id="faAnon_4">
+Form control objects all have a property named
+<code>&quot;form&quot;</code> that holds a reference to the
+<code>FORM</code> element that contains them. As a result the event
+handling functions attached to form controls can pass an anonymous
+reference to the form that contains them as <code>this.form</code>.
+Obviously a function called from an event handler on a control can
+be passes an anonymous reference to the control itself as
+<code>this</code>.
+</p>
+
+<h2 id="faBut">Radio Button and Other Control Collections</h2>
+
+<p id="faBut_1">
+Radio button controls work to provide a selection of one item of many
+when each of the radio button alternatives has the same
+<code>NAME</code> attribute. But it is also possible to give other types
+of control the same <code>NAME</code> attribute.
+</p>
+
+<p id="faBut_2">
+When controls that share the same <code>NAME</code> attribute they can
+still be accessed as integer indexed members of the <code>FORM</code>
+element's <code>elements</code> collection but when the member of the
+<code>elements</code> collection is accessed using the <code>NAME</code>
+attribute value as a property name browsers return a collection all of
+the elements with the corresponding NAME attributes. So given the <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span>:-
+</p>
+
+<pre id="faBut_ex1">
+&lt;form name=&quot;testForm&quot; action=&quot;http://example.com/somePage.jsp&quot;&gt;
+ &lt;ul style=&quot;list-style-type:none;&quot;&gt;
+ &lt;li&gt;&lt;input type=&quot;radio&quot; name=&quot;radioSet&quot; value=&quot;R1&quot;&gt;option 1&lt;/li&gt;
+ &lt;li&gt;&lt;input type=&quot;radio&quot; name=&quot;radioSet&quot; value=&quot;R2&quot;&gt;option 2&lt;/li&gt;
+ &lt;li&gt;&lt;input type=&quot;radio&quot; name=&quot;radioSet&quot; value=&quot;R3&quot;&gt;option 3&lt;/li&gt;
+ &lt;li&gt;&lt;input type=&quot;radio&quot; name=&quot;radioSet&quot; value=&quot;R4&quot;&gt;option 4&lt;/li&gt;
+ &lt;/ul&gt;
+ &lt;input type=&quot;submit&quot name=&quot;Submit_Button&quot; value=&quot;Send&quot;&gt;
+&lt;/form&gt;
+</pre>
+
+<p id="faBut_3">
+A property accessor referring to the member of the <code>FORM</code>'s
+<code>elements</code> collection by the property name
+<code>&quot;radioSet&quot;</code> will not return a reference to any one
+of the named radio buttons but instead returns a collection of all of the
+like-named radio controls.
+</p>
+
+<p id="faBut_4">
+The individual radio buttons within that collection are referred to as
+integer indexed members of that collection. So to find the button that
+is checked one might loop through all of the members of the collection
+of like-named radio buttons and copy a reference to the button with its
+<code>checked</code> property set to boolean <code>true</code>.
+</p>
+
+
+<pre id="faBut_ex2">
+var radioCollection, checkedButton;
+var frm = document.forms[&quot;testForm&quot;];
+if(frm){
+ radioCollection = frm.elements[&quot;radioSet&quot;];
+ if(radioCollection){
+ <span class="commentJS">/* The collection of like-named radio buttons has a length
+ property and that is used to limit a for loop:-
+ */</span>
+ for(var c = 0;c &lt; radioCollection.length;c++){
+ <span class="commentJS">/* The individual radio buttons are accessed as indexed
+ members of the collection using the loop counter - c
+ - from the for loop:
+ */</span>
+ if(radioCollection[c].checked){
+ <span class="commentJS">/* When a radio button element is found with its
+ checked property set to boolean true a reference
+ to that element is assigned to the local variable
+ - checkedButton - and the loop is terminated with
+ the - break - statement as only one button in a set
+ of like-named radio buttons will be checked at a
+ time, so any remaining buttons in the collection
+ must have checked properties set to false:
+ */</span>
+ checkedButton = radioCollection[c];
+ break;
+ }
+ }
+ if(checkedButton){
+ <span class="commentJS">/* Do something with the reference to the checked radio
+ button (if any).
+ */</span>
+ ...
+ }
+ }
+}
+</pre>
+
+<p id="faBut_5">
+It is not unusual when a form is generated by a server-side script that
+some forms may have one or more like-named controls. If there is only
+one control inserted in the form then accessing a member of the
+<code>elements</code> collection with its name will return a reference
+to that one control, but if there are multiple elements the returned
+reference will be to a collection of such controls. While it may be
+possible to branch client-side code that wants to interact with those
+controls to handle the two alternatives it adds an unnecessary
+maintenance burden to do so.
+</p>
+
+<p id="faBut_6">
+As handling a returned collection usually involves looping through that
+collection the simplest way of implementing the client-side code to
+deal with both collections and individual controls being returned by
+named properties of the <code>elements</code> collection is to
+normalise the references to individual controls so that they can be
+handled as if they were a collection. Looping through a collection
+involves using the <code>length</code> property of the collection to
+limit the loop statement and accessing the controls within the
+collection by integer index. This is exactly the way in which code
+would loop through the elements of an <code>Array</code>. To allow a
+script to handle both possibilities with the same code the return of
+a reference to an individual control could be detected and then that
+reference used to create a one-element <code>Array</code>. Subsequent
+code would then treat the <code>Array</code> as if it was a collection and
+loop through it, but as there is only one element the loop body would
+only be executed once.
+</p>
+
+<pre id="faBut_ex3">
+var radioCollection, checkedButton;
+var frm = document.forms[&quot;testForm&quot;];
+if(frm){
+ radioCollection = frm.elements[&quot;radioSet&quot;];
+ if(radioCollection){
+ <span class="commentJS">/* But the returned reference might not be a collection in this
+ case. Instead it may be a reference to just one control if
+ there is only one in this form with the name &quot;radioSet&quot;.
+ If it is a reference to an individual control it is going to
+ be necessary to normalise it. Because radio button controls
+ do not have - length - properties and collections do that is
+ the property that is going to be tested:
+ */</span>
+ if(typeof radioCollection.length != &quot;number&quot;){
+ <span class="commentJS">/* The length property is not a number so this cannot be a
+ collection and must be normalised so that the following
+ loop statement can handle it correctly. Normalisation is
+ done by making a reference to the control currently
+ referred to by the - radioCollection - local variable
+ into the first (and only) element of a new Array object
+ and then assigning a reference to that array to the -
+ radioCollection - local variable:
+ */</span>
+ radioCollection = [radioCollection];
+ }
+ <span class="commentJS">/* The execution of the body of the - for - loop is limited by
+ the - length - property of the collection/Array.
+ */</span>
+ for(var c = 0;c &lt; radioCollection.length;c++){
+ <span class="commentJS">/* The individual radio buttons are accessed as indexed
+ members of the collection/Array using the loop counter
+ - c - from the for loop:
+ */</span>
+ if(radioCollection[c].cheked){
+ checkedButton = radioCollection[c];
+ break;
+ }
+ }
+ if(checkedButton){
+ <span class="commentJS">/* do something with the reference to the checked radio
+ button (if any).
+ */</span>
+ ...
+ }
+ }
+}
+</pre>
+
+<p id="faBut_7">
+While it is normal for radio button controls to be like-named it is
+also possible for all other controls to be included in a form with
+multiple controls of the same type and like names. The same
+referencing techniques can be used with any type of control (even
+mixed types with like-names, though that is almost never done). But
+deciding whether a reference needs to be normalised by making it into
+the only element of an <code>Array</code> by testing the
+<code>length</code> property of that reference to see if it doesn't
+exist will not work with <code>SELECT</code> elements as they have
+a <code>length</code> property of their own. It also would not help
+to be testing some other characteristic of a collection, such as their
+<code>item</code> method, as <code>SELECT</code> elements usually have
+all of the methods and properties of a collection as they are
+implemented as collections of <code>OPTION</code> elements.
+</p>
+
+<p id="faBut_8">
+Turning the problem around and testing a returned reference to see if
+it has the characteristics of a <code>SELECT</code> element (such as
+an <code>options</code> property) would be better but some collection
+implementations have all of the properties and methods of the first
+element within that collection as well as the properties and methods
+of a collection (e.g. on IceBrowser 5). That means that it would not be
+easy to distinguish a collection of <code>SELECT</code> controls
+from an individual <code>SELECT</code> control. However, a more
+elaborate test might go:-
+</p>
+
+<pre id="faBut_ex4">
+<span class="commentJS">/* Normalise a reference that may be an individual from control
+ (including SELECT elements) or may be a collection of controls
+ into a form that can be handled in a - for - loop controlled with
+ its - length - property and accessed by integer index.
+*/</span>
+if((typeof contrlCollection.length != &quot;number&quot;)|| <span class="commentJS">//no length propety:</span>
+ <span class="commentJS">/* or:- */</span>
+ ((contrlCollection.options)&amp;&amp; <span class="commentJS">//it has an options colleciton and:</span>
+ ((!contrlCollection[0])|| <span class="commentJS">//no object at index 0 - not a collection</span>
+ <span class="commentJS">/* or:- */</span>
+ (contrlCollection[0] == contrlCollection.options[0])))){
+ <span class="commentJS">/* The object at index 0 in contrlCollection is the same object
+ as is at index 0 in contrlCollection.options so this must be
+ an individual SELECT element not a collection of them because a
+ collection of SELECT elements would not have an OPTION element
+ at index zero.
+ */</span>
+ contrlCollection = [contrlCollection];
+}
+</pre>
+
+<h2 id="faEff">Efficient use of Form Accessors</h2>
+
+<p id="faEff_1">
+Code that interacts with <code>FORM</code> elements and controls
+through the <code>document.forms</code> collection and the form's
+<code>elements</code> collection usually does not do enough work to
+make the efficiency of the code significant. But with large forms with
+many controls an inefficiently coded validation function (or some other
+interaction, like keeping running totals) can negatively impact on the
+user's experience. It can also be argued that considering the
+efficiency of implementation is a worthwhile habit even when it would
+make no perceivable difference.
+</p>
+
+<p id="faEff_2">
+A significant aspect of the efficient coding of form interacting code
+is the re-resolving of references to various objects. This trivial
+example code copies the values of 5 <code>INPUT</code> elements to
+local variables:-
+</p>
+
+<pre id="faEff_ex1">
+var txt1 = document.forms[&quot;formName&quot;].elements[&quot;field1&quot;].value;
+var txt2 = document.forms[&quot;formName&quot;].elements[&quot;field2&quot;].value;
+var txt3 = document.forms[&quot;formName&quot;].elements[&quot;field3&quot;].value;
+var txt4 = document.forms[&quot;formName&quot;].elements[&quot;field4&quot;].value;
+var txt5 = document.forms[&quot;formName&quot;].elements[&quot;field5&quot;].value;
+</pre>
+
+<p id="faEff_3">
+The shortcut accessors require the resolution of fewer object
+references:-
+</p>
+
+<pre id="faEff_ex2">
+var txt1 = document[&quot;formName&quot;][&quot;field1&quot;].value;
+var txt2 = document[&quot;formName&quot;][&quot;field2&quot;].value;
+var txt3 = document[&quot;formName&quot;][&quot;field3&quot;].value;
+var txt4 = document[&quot;formName&quot;][&quot;field4&quot;].value;
+var txt5 = document[&quot;formName&quot;][&quot;field5&quot;].value;
+</pre>
+
+<p id="faEff_4">
+But their use still involves re-resolving the form object each time a
+form control is accessed. It would be unnecessary to re-resolve this
+reference if a reference to the form was assigned to a local variable:-
+</p>
+
+<pre id="faEff_ex3">
+<span class="commentJS">/* Assign a reference to the form object to the local variable - frm -
+ and then make subsequent control references relative to that local
+ variable:
+*/</span>
+var frm = document.forms[&quot;formName&quot;];
+var txt1 = frm.elements[&quot;field1&quot;].value;
+var txt2 = frm.elements[&quot;field2&quot;].value;
+var txt3 = frm.elements[&quot;field3&quot;].value;
+var txt4 = frm.elements[&quot;field4&quot;].value;
+var txt5 = frm.elements[&quot;field5&quot;].value;
+</pre>
+
+<p id="faEff_5">
+The effect would be much the same as when a reference to the form
+object has been passed to a function and control references are
+accessed relative to the parameter holding the form reference.
+</p>
+
+<p id="faEff_6">
+It is still not optimum to be re-resolving the <code>elements</code>
+collection, and it is practical to assign a reference to that object
+to a local variable instead of a reference to the form object:-
+</p>
+
+<pre id="faEff_ex4">
+<span class="commentJS">/* Assign a reference to the form's elements collection to the local
+ variable - frmEls - and then make subsequent control references
+ relative to that local variable:
+*/</span>
+var frmEls = document.forms[&quot;formName&quot;].elements;
+var txt1 = frmEls[&quot;field1&quot;].value;
+var txt2 = frmEls[&quot;field2&quot;].value;
+var txt3 = frmEls[&quot;field3&quot;].value;
+var txt4 = frmEls[&quot;field4&quot;].value;
+var txt5 = frmEls[&quot;field5&quot;].value;
+</pre>
+
+<p id="faEff_7">
+With the original long form accessor the resolution starts with
+resolving the <code>&quot;document&quot;</code> identifier. The
+identifier is first looked for among the local variables of the
+function (as a named property of the internal
+&quot;Variable&quot; object, by ECMA specification),
+when it is not found the scope chain is searched, object by object
+down the chain, for a property with the corresponding name. When the
+scope resolution for <code>&quot;document&quot;</code> gets to the
+global object (at the end of the scope chain) it will find a property
+called <code>&quot;document&quot;</code>, a reference to the
+<code>document</code> object, and the first identifier in the accessor
+will have been resolved. The next identifier is
+<code>&quot;forms&quot;</code> and that is located as a property of the
+<code>document</code>. Then the <code>&quot;formName&quot;</code>
+property is identified in the <code>forms</code> collection. Next the
+<code>&quot;elements&quot;</code> property of the form is located,
+followed by the control name in that object and finally the
+<code>&quot;value&quot;</code> property of the control is returned.
+</p>
+
+<p id="faEff_8">
+When a reference to the <code>elements</code> collection is assigned to
+a local variable the first identifier in the property accessor is
+identified as that local variable, the control name is identified as a
+property of the <code>elements</code> collection referenced and the
+<code>&quot;value&quot;</code> property of the control is returned.
+</p>
+
+<p id="faEff_9">
+Obviously there is a big difference in the amount of work involved in
+acquiring the <code>value</code> of the control in each case. That
+difference will not be that significant if only a couple of values are
+accessed, but even with as few as half a dozen control property
+accesses the second approach will obviously be much more efficient,
+and with increasing numbers of controls the difference could easily
+become apparent to the user.
+</p>
+</body>
+</html>
/trunk/cljs/faq_notes/form_access.html
Property changes:
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: trunk/cljs/faq_notes/not_browser_detect.html
===================================================================
--- trunk/cljs/faq_notes/not_browser_detect.html (nonexistent)
+++ trunk/cljs/faq_notes/not_browser_detect.html (revision 43)
@@ -0,0 +1,1413 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html lang="en">
+<head>
+<title>Browser Detection (and What to Do Instead)</title>
+<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+<link href="../../faq.css" rel="stylesheet" type="text/css">
+<link href="../notes.css" rel="stylesheet" type="text/css">
+<style type="text/css">
+.tip {
+ border: 1px solid #ccc;
+ padding: 1ex;
+ background: #fcfcfc;
+ font-size: 90%;
+}
+</style>
+</head>
+<body>
+<h1 id="bdTop">Browser Detection (and What to Do Instead)</h1>
+<div id="faqNav">
+ <a href="../../">FAQ</a> &gt; <a href="../">FAQ Notes</a>
+</div>
+<p>
+By Richard Cornford, edited by Garrett Smith
+</p>
+<ul>
+ <li><a href="#bdIntro">Introduction</a></li>
+ <li><a href="#bdValid">Avoiding Structural Differences in the Browser DOMs</a></li>
+ <li><a href="#bdDif">Browsers Differences</a></li>
+ <li><a href="#bdFailS">Failed Strategies: Browser Detecting</a>
+ <ul>
+ <li><a href="#bdUAS">Assumptions Based on navigator.userAgent</a></li>
+ <li><a href="#bdOI">Assumptions Based on DOM Objects: Object inference</a></li>
+ </ul>
+ </li>
+ <li><a href="#bdFD">A Strategy That Works: Object/Feature Detecting.</a>
+ <ul>
+ <li><a href="#bdGEID">Example 1: IDed Element Retrieval</a></li>
+ <li><a href="#bdScroll">Example 2: Scroll Values</a></li>
+ <li><a href="#bdReplace">Example 3: String.prototype.replace</a></li>
+ </ul>
+ </li>
+ <li><a href="#bdDesPb">The Javascript Design Problem</a></li>
+
+</ul>
+
+<h2 id="bdIntro">Introduction</h2>
+
+<p id="bdIntro_1">
+Under normal circumstances computer programs are written for a known
+environment. The programmer knows what to expect; which APIs will be
+available, how they will behave and so on. Java is an ideal example
+of this, providing a theoretically consistent set of APIs and language
+features across all Java Virtual Machine (JVM) implementations. But
+this is also true in most other circumstances. The programmer of C++
+for the Windows operating system will know what MFC classes are
+available and how to program them. Their expectations will be
+rewarded, if they posses the required knowledge.
+</p>
+
+<p id="bdIntro_2">
+Client side javascript for the Internet, on the other hand, has the
+possibly unique problem of having to be authored with no specific
+knowledge of the environment in which it will be executed. The
+client side environment will usually be a web browser and web
+browsers do tend to have many common features (and increasingly
+standardised features) but the author cannot know which version of
+which browser will be making any HTTP request (or
+whether it is a browser at all). It is not even possible to tell in
+advance whether the User Agent will be capable of executing
+javascript; all of those that can include a user configurable option
+to disable it anyway.
+</p>
+
+<p id="bdIntro_3">
+Javascript authors for the Internet must realise that they are dealing
+with the unknown and that any, and all, scripts will fail to execute
+somewhere. The challenge is to get the most from your javascript when
+it is available but to cope with their failure in a meaningful way.
+</p>
+
+<p id="bdIntro_4">
+I once read a description of a variant on the game of chess, played
+at military academies. Two players sit at separate boards set up with
+only their own pieces, out of sight of each other, and a referee
+supervises the game. Each player makes their move in turn and the
+referee is responsible for informing them how the other's move impacts
+on their own pieces and how the other's disposition of pieces impact
+on their intended move. The player is informed only when one of their
+own pieces is taken, when one of their moves is affected by
+interacting with one of their opponents pieces (i.e. a player may want
+to move a bishop across the board but the referee may inform them that
+their move was stopped four squares early when the bishop took a pawn
+from the other side) and when one of their opponents pieces is
+sitting on a square adjacent to one of their own.
+</p>
+
+<p id="bdIntro_5">
+The game is used to teach battlefield strategy. To win a player must
+probe and test to deduce his opponent's disposition, while planing and
+executing a response that will achieve the desired checkmate. It is
+this sort of strategy that needs to be added to the normal programming
+problems in order that javascript may cope with its unknown execution
+environment, with the significant difference that the strategy, its
+tests and all of the paths of execution must be fully planed out before
+the code can even starts executing.
+</p>
+
+<h2 id="bdValid">Avoiding Structural Differences in the Browser DOMs</h2>
+
+<p id="bdValid_1">
+While the point of this article is to introduce techniques for handling
+the differences between web browsers and their DOM implementations it
+is also possible to avoid some types of differences especially related
+to the structure of the DOM that is being scripted.
+</p>
+
+<p id="bdValid_2">
+If I was asked to recommend one action most likely to promote the
+authoring of cross-browser scripts it would be: <strong><em>Start
+from a basis of valid <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language"
+>HTML</abbr></span></em></strong>.</p>
+
+<p id="bdValid_3">
+Browsers presented with invalid <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> will usually attempt to error
+correct it in order to do the best possible job of displaying it.
+Some browsers, particularly IE, are tolerant of all sorts of strange
+formulations of mark-up. Valid <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> has a tree-like structure, elements
+may completely contain others but they cannot overlap, and there are
+rules about which elements may appear in which contexts. The DOM that
+is to be scripted also has a tree-like structure and there is a very
+simple relationship between the tree-like structure of valid <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> and
+the DOM constructed from it. So any browser presented with valid <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span>
+will be able to directly translate that <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> into a corresponding DOM
+using well specified rules, resulting in a DOM that is of predictable
+and consistent structure on all of the browsers that can build a DOM.
+</p>
+
+<p id="bdValid_4">
+Invalid <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> will not translate as naturally into a DOM, or even a
+tree-like structure. If the browser is going to build a DOM with the
+source provided it is going to have to apply error correcting rules
+and attempt to build the best DOM it can. But the error correcting
+rules are not standardised, not even published. So different browsers
+have no choice but apply different rules and that directly results in
+the building of DOMs with different (and in extremes, radically
+different) structures.
+</p>
+
+<p id="bdValid_5">
+As a result, using invalid <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> directly produces differences in the
+DOMs produced by different browsers. No matter how good the application
+of techniques for dealing with the differences between browsers, it
+does not make sense to do anything that will provoke more differences
+than are unavoidable.
+</p>
+
+<p id="bdValid_6">
+The authoring of invalid <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span>, justified because &quot;It works in
+browser XYZ&quot;, gives the authors of accompanying scripts the
+impression that cross-browser scripting is harder than it is. If they
+had started with valid <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> they would never have encountered any of
+the structural inconsistencies that invalid <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> can provoke.
+</p>
+
+<h2 id="bdDif">Browsers Differences</h2>
+
+<p id="bdDif_1">
+As browsers have evolved they have offered more features to javascript.
+Different manufactures have adopted the features of other browsers,
+while adding new features, that may in turn have been adopted by (or
+will be adopted by) their competitors. Various sets of common features
+have emerged and some have been formalised by the W3C into a sequence
+of standard DOM specifications. Along the way an increasing number of
+javascript capable browsers have emerged. In addition to desktop PC
+browsers, javascript capable browsers exist for a whole range of
+devices; PDAs, mobile telephones (Microwave ovens, refrigerators).
+</p>
+
+<p id="bdDif_2">
+Unfortunately it is the case that the browsers on the smaller devices
+cannot offer the range of features available to a desktop PC and even
+as the technology improves and features are added to the smaller
+browsers the problem will not improve as browsers will become available
+on a wider range of devices while the desktop PC browsers will continue
+to march ahead of them.
+</p>
+
+<p id="bdDif_3">
+Over the years various strategies have been attempted to tackle this
+problem and some have failed miserably.
+</p>
+
+<h2 id="bdFailS">Failed Strategies: Browser Detecting</h2>
+
+<h3 id="bdUAS">Assumptions Based on navigator.userAgent</h3>
+
+<p id="bdUAS_1">
+One of the most popular strategies for handling the differences between
+web browsers was browser detecting based on the User Agent string.
+Browsers possessing a <code>navigator</code> object also provide a
+property of that object: <code>navigator.userAgent</code> containing a
+string that (in theory) identifies the browser. Its application went
+something like:-
+</p>
+
+<pre id="bdUAS_ex1">
+<span class="commentJS">/* Warning: never use this script, or any script based on, or resembling, it.
+*/</span>
+var userAgent = self.navigator.userAgent;
+var appName = self.navigator.appName;
+var isOpera = false;
+var isOpera5 = false;
+var isOpera6p = false;
+var isIE = false;
+var isIE4 = false;
+var isIE5p = false;
+var isMozilla1p = false;
+var isNet4 = false;
+var isNet5p = false;
+var operaVersion = 0;
+var ieVersion = 0;
+var appVersion = self.navigator.appVersion;
+var brSet = false;
+
+function brSetup(){
+ for(var c = 3;c &lt; appVersion.length;c++){
+ var chr = appVersion.charAt(c);
+ if(isNaN(chr)){
+ appVersion = appVersion.substring(0, c);
+ break;
+ }
+ }
+ if((userAgent.indexOf('webtv') &lt; 0) &amp;&amp;
+ (userAgent.indexOf('hotjava') &lt; 0)){
+ if(userAgent.indexOf('Opera') &gt;= 0){
+ var ind = (userAgent.indexOf('Opera')+6);
+ if(((ind+1) &lt; userAgent.length)&amp;&amp;(ind &gt;= 6)){
+ isOpera = true;
+ var bsVersion = parseInt(userAgent.substring(ind, ind+1));
+ if(!isNaN(bsVersion)){
+ operaVersion = bsVersion;
+ if(operaVersion &gt;= 6){
+ isOpera6p = true;
+ }else if(operaVersion &gt;= 5){
+ isOpera5 = true;
+ }
+ }
+ }
+ }else if(appName.indexOf('Microsoft Internet Explorer') &gt;= 0){
+ var ind = (userAgent.indexOf('MSIE')+5);
+ if(((ind+1) &lt; userAgent.length)&amp;&amp;(ind &gt;= 5)){
+ isIE = true;
+ var bsVersion = parseInt(userAgent.substring(ind, ind+1));
+ if(!isNaN(bsVersion)){
+ ieVersion = bsVersion;
+ if(ieVersion &gt;= 5){
+ isIE5p = true;
+ }else if(ieVersion &gt;= 4){
+ isIE4 = true;
+ }
+ }
+ }
+ }else if(appName.indexOf('Netscape') &gt;= 0){
+ if((self.navigator.vendor)&amp;&amp;
+ (self.navigator.vendor.indexOf('Netscape') &gt;= 0)&amp;&amp;
+ (userAgent.indexOf('Gecko') &gt;= 0)){
+ isNet5p = true;
+ }else if((userAgent.indexOf('Netscape') &lt; 0)&amp;&amp;
+ (userAgent.indexOf('Gecko') &gt;= 0)&amp;&amp;
+ (appVersion &gt;= 5)){
+ isMozilla1p = true;
+ }else if((appVersion &lt; 5)&amp;&amp;
+ (userAgent.indexOf('compatible') &lt; 0)){
+ isNet4 = true;
+ }
+ }
+ }
+ brSet = true;
+}
+</pre>
+
+<p id="bdUAS_2">
+This version also uses some other properties of the
+<code>navigator</code> object; <code>appName</code> and
+<code>appVersion</code>.
+</p>
+
+<p id="bdUAS_3">
+Superficially this type of script seems to be saying quite a lot about
+what browser is executing the script. Knowing that the
+<code>isIE5p</code> variable is boolean <code>true</code> seems to be
+a reasonable indicator that the browser in question is Internet
+Explorer Version 5 or above and from that all of the available features
+on the IE 5+ DOM could be assumed to exist.
+</p>
+
+<p id="bdUAS_4">
+Unfortunately, if this type of script ever was an effective determiner
+of the browser type, it is not now. The first problem is that you cannot
+write this type of script to take into account all web browsers. The
+script above is only interested in Internet Explorer, Netscape and
+(some) Mozilla derived browsers and Opera. Any other browser will not
+be identified, and that will include a number of W3C DOM conforming
+fully dynamic visual browsers quite capable of delivering on even quite
+demanding code.
+</p>
+
+<p id="bdUAS_5">
+The second problem is that scripts like this one, and server-side
+counter-parts (reading the HTTP User Agent header) were used to
+<em>exclude</em> browsers that did not fall into a set of browsers
+known to the author, regardless of whether those browsers were
+capable of displaying the offending site or not.
+</p>
+
+<p id="bdUAS_6">
+As more browsers were written, their authors discovered that if they
+honestly reported their type and version in their User Agent string
+they would likely be excluded from sites that they would
+otherwise be quite capable of displaying. To get around this problem
+browsers began spoofing the more popular versions, sending HTTP User
+Agent headers, and reporting <code>navigator.userAgent</code> strings,
+that were indistinguishable from, say, IE.
+</p>
+
+<p id="bdUAS_7">
+As a result, when the above script reports <code>isIE5p</code> as true, it is
+possible that the browser that is executing the script is one of
+numerous current browsers. Many of those browsers support sufficient
+features found on IE5+ to allow most scripts to execute but the
+trueness of <code>isIE5p</code> is not a valid indicator that the
+browser will support <em>all</em> of the IE 5+ DOM.
+</p>
+
+<p id="bdUAS_8">
+Now you might decide that a browser that lies about its identity
+deserves what it gets (though they started lying in order to make
+themselves usable in the face of near-sighted <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> and script authors)
+but is worth bearing in mind that the IE 5
+<code>navigator.userAgent</code> string is:
+<code>&quot;Mozilla/4.0 (compatible; MSIE 5.01; Windows NT)&quot;</code>.
+IE 5 is in fact spoofing Netscape 4, and Microsoft started to do that
+for precisely the same reasons that motivate many current browsers to
+send User Agent headers, and report <code>navigator.userAgent</code>
+strings that are indistinguishable form those of Microsoft browsers.
+</p>
+
+<p id="bdUAS_9">
+No browser manufacture wants (or ever has wanted) their browser to be
+needlessly excluded from displaying a web site that it is perfectly
+capable of handling just because the author of that site does not
+know it by name. And to prevent that they have followed Microsoft and
+taken action that has rendered the <code>userAgent</code> string (and
+the HTTP User Agent header) meaningless.
+</p>
+
+<p id="bdUAS_10">
+We are now at a point where the contents of the User Agent strings
+bear no relationship at all to the capabilities and features of the
+browser that is reporting it. The situation has gone so far that a
+number of javascript experts have stated that a standard quality test
+for an unknown script would include searching the source code of the
+script for the string <code>&quot;userAgent&quot;</code> and dismissing
+the script out of hand if that string is found.
+</p>
+
+<h3 id="bdOI">Assumptions Based on DOM Objects: Object inference</h3>
+
+<p id="bdOI_1">
+A second browser detecting strategy uses the objects present in various
+browser DOMs and make the assumption that the presence (or absence) of
+one or more objects indicates that a browser is a particular type or
+version. I quickly found this example of typical code of this type:-
+</p>
+
+<pre id="bdOI_ex1">
+<span class="commentJS">/* Warning: never use this script, or any script based on, or resembling, it.
+*/</span>
+var isDOM=(document.getElementById)?true:false;
+var isIE4=(document.all&amp;&amp;!isDOM)?true:false;
+var isIE5p=(document.all&amp;&amp;isDOM)?true:false;
+var isIE=(document.all)?true:false;
+var isOP=(window.opera)?true:false;
+var isNS4=(document.layers)?true:false;
+</pre>
+
+<p id="bdOI_2">
+Javascript performs automatic type conversion so when a boolean result
+is expected from an expression that evaluates to a non-boolean value
+that non-boolean value is (internally) converted to a boolean value
+(using the rules defined in the ECMAScript specification) and that
+boolean is used as the result.
+</p>
+
+<p id="bdOI_3">
+Take the first line:-
+</p>
+
+<pre id="bdOI_ex2">
+var isDOM=(document.getElementById)?true:false;
+</pre>
+
+<p id="bdOI_4">
+The conditional expression requires that the expression preceding the <code>?</code>
+have a boolean result. The <code>document.getElementById</code>
+property accessor can resolve as one of two values depending on whether
+the <code>getElementById</code> function is supported in the browser in
+question. If it is supported then the accessor resolves as a function
+object, and is type converted to boolean <code>true</code>. If
+<code>getElementById</code> is not supported the accessor resolves as
+undefined, and undefined type converts to boolean
+<code>false</code>. Thus the expression preceding the question mark
+resolves as <code>true</code> or <code>false</code> and based on that
+result <code>true</code> or <code>false</code> are assigned to the
+variable <code>isDOM</code>.
+</p>
+
+<div class="tip">
+ <h4>Boolean Conversion Tip: !!</h4>
+ <p id="bdOI_5">
+ Incidentally, this code is not the optimum method of assigning a boolean
+ value based on the type converted to boolean result of a property accessor.
+ It is better to use the javascript NOT operator ( <code>!</code> ) twice
+ or to pass the object reference as the argument to the <code>Boolean</code>
+ constructor called as a function. The not operator will type convert its
+ operand to boolean and then invert it so <code>false</code> becomes
+ <code>true</code> and <code>true</code> becomes <code>false</code>.
+ Passing that result as the operand for a second not operator inverts
+ the boolean again so a reference to a function object results in boolean
+ <code>true</code> and an undefined reference results in boolean
+ <code>false</code>. The <code>Boolean</code> constructor called as a
+ function converts its argument to boolean and returns that value. The
+ statement would become:-
+ </p>
+
+ <pre id="bdOI_ex3">
+ var isDOM = !!document.getElementById;
+
+ <span class="commentJS">/* - or - */</span>
+
+ var isDOM = Boolean(document.getElementById);
+ </pre>
+
+ <p id="bdOI_6">
+ Which is shorter and faster than the original version and certainly
+ more direct.
+ </p>
+</div>
+
+<h4>Inductive Generalization Fallacy</h4>
+<p id="bdOI_7">
+The problem with this type of browser detecting script is that it is
+used to make assumptions about the browser's capabilities that are
+rarely valid. For example, this <code>isDOM</code> result, based on
+the browser's support for <code>document.getElementById</code>, is
+often used as the basis for the assumption that the browser has a
+fully dynamic DOM with methods such as
+<code>document.createElement</code>, <code>replaceChild</code> and
+<code>appendChild</code>. Browsers do not live up to that expectation,
+some are not that dynamic and while they may implement some of the Core
+DOM level 1 methods such as <code>getElementById</code> They do not
+necessarily implement large parts of the various DOM standards,
+including all of the dynamic <code>Node</code> manipulation methods.
+</p>
+
+<p id="bdOI_8">
+The result of the <code>isIE5p</code> test is intended to indicate that
+the browser is Internet Explorer 5.0 or above. However, Opera 7,
+IceBrowser 5.4, Web Browser 2.0 (palm OS), Konquerer, Safari, NetFront,
+iCab and others will all produce a <code>true</code> value in
+<code>isIE5p</code> because they implement <code>getElementById</code>
+and the <code>document.all</code> collection. As a result, code that
+assumes that it will have <em>all</em> of the capabilities of IE 5.0+
+available to it when <code>isIE5p</code> is <code>true</code> will as
+often as not be mistaken.
+</p>
+
+<p id="bdOI_9">
+This problem applies to all of the tests above with the possible
+exception of the <code>window.opera</code> test. I am unaware of a
+second browser type that has implemented an <code>opera</code> object
+on the window object. But then Opera 7 is a radically different, and
+much more dynamic browser that its preceding versions, though they all
+possess a <code>window.opera</code> object.
+</p>
+
+<p id="bdOI_10">
+To get around the problem that multiple browsers implement the same
+features (even if they start off unique to one browser) script authors
+have attempted to find more discriminating features to test. For
+example, the following script extract is intended to work only on IE
+5.0+ browsers:-
+</p>
+
+<pre id="bdOI_ex4">
+var isIE5p = !!window.ActiveXObject;
+...
+function copyToClip(myString){
+ if(!isIE5p) return;
+ window.clipboardData.setData(&quot;text&quot;,myString);
+}
+</pre>
+
+<p id="bdOI_11">
+The <code>ActiveXObject</code> constructor is intended to be
+discriminating of an IE browser. However, this type if script still
+does not work. It has placed the competing browser manufacturers in
+exactly the same position as they were in when scripts tested the
+<code>navigator.userAgent</code> string and excluded them from
+accessing a site because they honestly reported that they where not
+IE. As a result I already know of one browser that has implemented
+a <code>window.ActiveXObject</code> function, it probably is a dummy
+and exists in the browsers DOM specifically to defeat the exclusion
+of that browser based on tests like the one above.
+</p>
+
+<p id="bdOI_12">
+The assumptions that the existence of one (or two) feature(s) in a
+javascript environment infers the existence of any feature beyond
+the ones tested is invalid. It is only used by those ignorant of the
+potential for diversity, imitation and the patterns of evolution in
+browser DOMs.
+</p>
+
+<p id="bdOI_13">
+No matter how specifically the objects from which the inferences are
+derived are chosen, the technique itself sows the seeds of its own
+invalidity, an object that may actually validly be used to infer that
+a browser is of a particular type/version today probably will not still
+be valid next year. Adding a maintenance burden to a task that already
+presupposes an omniscient knowledge of <em>all</em> browser DOMs just
+in order to be effectively implemented at present.
+</p>
+
+
+<h2 id="bdFD">A Strategy That Works: Object/Feature Detecting</h2>
+
+<p id="bdFD_1">
+The main point of the previous discussion is to convey the idea that it
+is impossible to detect exactly which type of browser (or version of
+that browser) a script is being executed on. The use that such scripts
+have been put to in the past (to exclude browsers from sites that
+they probably could have successfully handled) has motivated the
+manufactures of browsers to render browser detecting nonviable
+as a strategy for dealing with the variations in browser DOMs.
+</p>
+
+<p id="bdFD_2">
+Fortunately, not being able to identify a web browser type or version
+with more accuracy than could be achieved by generating a random number
+and then biasing the result by your favourite (meaningless, because
+they too are based on browser detecting and suffer exactly the same
+unreliability) browser usage statistics, does not need to impact upon
+your ability to script web browsers at all. A viable alternative
+strategy has been identified and developed to the point where it is
+possible to author javascript to be used on web pages without any
+interest in the type or version of the browser at all.
+</p>
+
+<p id="bdFD_3">
+That alternative strategy is known as object or feature detecting. I
+prefer to use the term &quot;feature detecting&quot;, partly because the
+resulting code often needs to test and probe a wider range of
+features than just those that could be described as objects, but
+mostly because &quot;object detecting&quot; is occasionally
+erroneously applied to the object inference style of script described
+above.
+</p>
+
+<p id="bdFD_4">
+Feature detecting seeks to match an attempt to execute as script (or a
+part of a script) with the execution environment by seeking to test
+features of that environment where the results of the test have a
+direct one-to-one relationship with the features that need to be
+supported in the environment for the code to successfully execute. It
+is the direct one-to-one relationship in the implemented tests that
+avoids the need to identify the specific browser because whatever
+browser it is it either will support all of the required features or
+it will not. That would mean testing the feature itself (to ensure
+that it exists on the browser) and possibly aspects of the behaviour
+of that feature.
+</p>
+
+<p id="bdFD_5">
+Taking the previous example that illustrated how the
+<code>ActiveXObject</code> constructor might be used as the basis for
+a script that inferred the existence of, and ability to use, the
+<code>clipboardData</code> feature implemented on window IE. Rather
+than inferring the browser's support for the <code>clipboardData</code>
+feature from some other unrelated feature it should be fairly obvious
+that the feature that should be tested for prior to attempting to write
+to the clipboard <em>is</em> the <code>clipboardData</code> object, and
+further, that calling the <code>setData</code> method of that object
+should necessitate checking that it too is implemented:-
+</p>
+
+<pre id="bdFD_ex1">
+function copyToClip(myString){
+ if((typeof clipboardData != 'undefined')&amp;&amp;
+ (clipboardData.setData)){
+ clipboardData.setData(&quot;text&quot;,myString);
+ }
+}
+</pre>
+
+<p id="bdFD_6">
+In this way the tests that determine whether the
+<code>clipboardData.setData</code> method is called have a direct
+one-to-one relationship with the browser's support for the feature. It
+is not necessary to be interested in whether the browser is the
+expected windows IE that is known to implement the feature, or whether
+it is some other browser that has decided to copy IE's implementation
+and provide the feature itself. If the feature is there (at least to
+the required extent) it is used and if it is not there no attempt is
+made to use it.
+</p>
+
+<p id="bdFD_7">
+The above feature detecting tests are done using two operations. The
+first employs the <code>typeof</code> operator, which returns a string
+depending on the type of its operand. That string is one of
+<code>&quot;undefined&quot;</code>, <code>&quot;object&quot;</code>,
+<code>&quot;function&quot;</code>, <code>&quot;boolean&quot;</code>
+<code>&quot;string&quot;</code> and <code>&quot;number&quot;</code>
+and the test compares the returned string with the string
+<code>&quot;undefined&quot;</code>. The <code>clipboardData</code>
+object is not used unless typeof does not return
+<code>&quot;undefined&quot;</code>.
+</p>
+
+
+<p id="bdFD_8">
+The second test is a type-converting test. The logical AND
+(<code>&amp;&amp;</code>) operator internally converts its operands to
+boolean in order to make its decision about what value it will return.
+If <code>clipboardData.setData</code> is undefined it will type-convert
+to boolean <code>false</code>, while if it is an object or a function
+the result of the conversion will be boolean <code>true</code>.
+</p>
+
+<p id="bdFD_9">
+However, that function is not a particularly clever application of
+feature detecting because, while it avoids the function throwing errors
+in an attempt to execute <code>clipboardData.setData</code> on a browser
+thatdoes not support it, it will do nothing on a browser that does not
+support it. That is a problem when the user has been presented with a
+GUI component that gives them the impression that their interaction
+will result in something being written to the clipboard but when they
+use it nothing happens. And of course nothing was going to happen if
+the browser in use did not support javascript or it had been disabled.
+</p>
+
+<p id="bdFD_10">
+Ensuring that a script will not attempt to use a feature that is not
+supported is not sufficient to address the design challenge of crating
+scripts for the Internet. Testing the browser for the features that it
+does support makes it practical to handle a spectrum of browser DOMs
+but the script design task also involves planning how to handle the
+range of possibilities. A range that goes from guaranteed failure to
+execute at all on browser that do not support javascript, to full
+support for all of the required features.
+</p>
+
+<p id="bdFD_11">
+You can tell when the browser does not support the
+<code>clipboardData</code> feature from the script prior to using it
+but the user has no way of knowing why a button that promised them
+some action has failed to do anything. So in addition to matching the
+script to the browser's ability to execute it, it is also necessary to
+match the GUI, and the user's resulting expectations, to what the
+script is going to be able to deliver.
+</p>
+
+<p id="bdFD_12">
+Suppose the <code>copyToClip</code> function was called from an
+<code>INPUT</code> element of <code>type=&quot;button&quot;</code>
+and was intended to copy a company e-mail address into the clipboard,
+the <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> code for the button might look like:-
+</p>
+
+<pre id="bdFD_ex2">
+&lt;input type=&quot;button&quot;
+ value=&quot;copy our contact e-mail address to your clipboard&quot;
+ onclick=&quot;copyToClip('info@example.com')&quot;&gt;
+</pre>
+
+<p id="bdFD_13">
+We know that that <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> will do nothing if javascript is
+disabled/unavailable and we know that it will do nothing if the browser
+does not support the required features, so one option would be to use a
+script to write the button <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> into the document in the position in
+which the button was wanted when the browser provided the facility:-
+</p>
+
+<pre id="bdFD_ex3">
+&lt;script type=&quot;text/javascript&quot;&gt;
+ if((typeof clipboardData != 'undefined')&amp;&amp;
+ (clipboardData.setData)&amp;&amp;
+ (document.write)){
+ document.write('&lt;input type=&quot;button&quot;',
+ 'value=&quot;copy our contact e-mail address',
+ ' to your clipboard&quot; onclick=&quot;',
+ 'copyToClip(\'info@example.com\')&quot;&gt;');
+ }
+&lt;/script&gt;
+</pre>
+
+<p id="bdFD_14">
+Now the user will never see the button unless the browser supports the
+required features <em>and</em> javascript is enabled. The user never
+gets an expectation that the script will not be able to deliver (at
+least that is the theory, it is still possible for the user's browser
+configuration to prevent scripts from writing to the clipboard, but
+the user might be expected to know how their browser is configured and
+understand that the button is not in a position to override it).
+</p>
+
+<p id="bdFD_15">
+If the <code>copyToClip</code> function is only ever called from
+buttons that are written only following the required feature detection
+then it can be simplified by the removal of the test from its body as
+it would be shielded from generating errors on nonsupporting browsers by
+the fact that there would be no way for it to be executed.
+</p>
+
+<p id="bdFD_16">
+The <code>document.write</code> method is not the only way of adding
+GUI components to a web page in a way that can be subject to the
+verification of the features that render those components meaningful.
+Alternatives include writing to a parent element's
+<code>innerHTML</code> property (where supported, see
+<a href="/faq/#updateContent">FAQ: How do I modify the content of the current page?</a>), or using the W3C DOM
+<code>document.crateElement</code> (or <code>createElementNS</code>)
+methods and appending the created element at a suitable location within
+the DOM. Either of these two approaches are suited to adding the
+components after the page has finished loading, but that can be useful
+as some feature testing is not practical before that point. The
+approach used can be chosen based on the requirements of the script.
+If the script is going to be using the
+<code>document.createElement</code> method itself then it is a good
+candidate as a method for inserting any required GUI components,
+similarly with <code>innerHTML</code>. The <code>document.write</code>
+method is universally supported in <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> DOMs but is not necessarily
+available at all in XHTML DOMs.
+</p>
+
+<p id="bdFD_17">
+Other ways of handling the possibility that the browser will not
+support either javascript or the features required by the script used
+is to design the <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span>/<span class="initialism" title="Cascading Style Sheet"><abbr title="Cascading Style Sheet">CSS</abbr></span> parts of the page so that the script, upon
+verifying support for the features it requires, can modify, manipulate
+and transform the resulting elements in the DOM. But in the absence of
+sufficient script support the unmodified <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> presents all of the
+required content, navigation, etc.
+</p>
+
+<p id="bdFD_18">
+This can be particularly significant with things like navigation menus.
+One style of design would place the content of the navigation menus,
+the URLs and text, in javascript structures such as Arrays. But either
+of javascript being disabled/unavailable on the client or the absence
+of the features required to support a functional javascript menu would
+leave the page without any navigation at all. Generally that would not
+be a viable web page, and not that good for search engine placement as
+search engine robots do not tend to execute javascript either so they
+would be left unable to navigate a site featuring such a menu and so
+unable to rank its content for listing.
+</p>
+
+<p id="bdFD_19">
+A better approach to menu design would have the navigation menu content
+defined in the <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span>, possibly as nested list elements of some sort, and
+once the script has ascertained that the browser is capable of executing
+it and providing the menu in an interactive form it can modify the <span class="initialism" title="Cascading Style Sheet"><abbr title="Cascading Style Sheet">CSS</abbr></span>
+<code>position</code>, <code>display</code> and <code>visibility</code>
+properties, move the elements to their desired location, attach event
+handlers and generally get on with the task of providing a javascript
+menu. And the worst that happens when the browser does not support
+scripting or the required features is that the user (and any search
+engine robots) finds the navigation in the page as a series of nested
+lists containing links. Fully functional, if not quite as impressive as
+it could have been had the script been supported. This is termed
+&quot;clean degradation&quot; and goes hand in hand with feature
+detecting during the process of planing and implementing a browser
+script for the Internet.
+</p>
+
+<h3 id="bdGEID">Example 1: IDed Element Retrieval</h3>
+
+<p id="bdGEID_1">
+An important aspect of feature detecting is that it allows a script to
+take advantage of possible fall-back options. Having deduced that a
+browser lacks the preferred feature it still may be possible to
+achieve the desired goal by using an alternative feature that is know
+to exist on some browsers. A common example of this is retrieving an
+element reference from the DOM given a string representing the
+<code>ID</code> attribute of that element. The preferred method would
+be the W3C Core DOM standard <code>document.getElementById</code>
+method which is supported on the widest number of browsers. If that
+method was not available but the browser happened to support the
+<code>document.all</code> collection then it could be used for the
+element retrieval as a fall-back option. And for some types of
+elements, such as <span class="initialism" title="Cascading Style Sheet"><abbr title="Cascading Style Sheet">CSS</abbr></span> positioned elements on Netscape 4 (where the
+<code>document.layers</code> collection may be used to retrieve such
+a reference), additional options may be available.
+</p>
+
+<pre id="bdGEID_ex1">
+function getElementWithId(id){
+ var obj;
+ if(document.getElementById){
+ <span class="commentJS">/* Prefer the widely supported W3C DOM method, if
+ available:-
+ */</span>
+ obj = document.getElementById(id);
+ }else if(document.all){
+ <span class="commentJS">/* Branch to use document.all on document.all only
+ browsers. Requires that IDs are unique to the page
+ and do not coincide with NAME attributes on other
+ elements:-
+ */</span>
+ obj = document.all[id];
+ }else if(document.layers){
+ <span class="commentJS">/* Branch to use document.layers, but that will only work for
+ <span class="initialism" title="Cascading Style Sheet"><abbr title="Cascading Style Sheet">CSS</abbr></span> positioned elements and LAYERs that are not nested. A
+ recursive method might be used instead to find positioned
+ elements within positioned elements but most DOM nodes on
+ document.layers browsers cannot be referenced at all.
+ */</span>
+ obj = document.layers[id];
+ }
+ <span class="commentJS">/* If no appropriate/functional element retrieval mechanism
+ exists on this browser this function returns null:-
+ */</span>
+ return obj||null;
+}
+</pre>
+
+<p id="bdGEID_2">
+Although that function is not very long or complex (without its
+comments) it does demonstrate a consequence of one style of
+implementation of feature detecting, it repeats the test each time
+it is necessary to retrieve an element using its ID. If not too many
+elements need retrieving that may not be significant, but if many
+elements needed retrieving in rapid succession and performance was
+significant then the overhead of performing the feature detection on
+each retrieval may add up and impact on the resulting
+script.
+</p>
+
+<p id="bdGEID_3">
+An alternative is to assign one of many functions to a global
+<code>getElementWithId</code> variable based on the results of the
+feature detecting tests, as the script loads.
+</p>
+
+<pre id="bdGEID_ex2">
+var getElementWithId;
+if(document.getElementById){
+ <span class="commentJS">/* Prefer the widely supported W3C DOM method, if
+ available:-
+ */</span>
+ getElementWithId = function(id){
+ return document.getElementById(id);
+ }
+}else if(document.all){
+ <span class="commentJS">/* Branch to use document.all on document.all only
+ browsers. Requires that IDs are unique to the page
+ and do not coincide with NAME attributes on other
+ elements:-
+ */</span>
+ getElementWithId = function(id){
+ return document.all[id];
+ }
+}else if(document.layers){
+ <span class="commentJS">/* Branch to use document.layers, but that will only work for <span class="initialism" title="Cascading Style Sheet"><abbr title="Cascading Style Sheet">CSS</abbr></span>
+ positioned elements. This function uses a recursive method
+ to find positioned elements within positioned elements but most
+ DOM nodes on document.layers browsers cannot be referenced at
+ all. This function is expected to be called with only one
+ argument, exactly like the over versions.
+ */</span>
+ getElementWithId = function(id, baseLayers){
+ <span class="commentJS">/* If the - baseLayers - parameter is not provided default
+ its value to the document.layers collection of the main
+ document:
+ */</span>
+ baseLayers = baseLayers||document.layers;
+ <span class="commentJS">/* Assign the value of the property of the - baseLayers -
+ object (possibly defaulted to the document.layers
+ collection) with the property name corresponding to the
+ - id - parameter to the local variable - obj:
+ */</span>
+ var obj = baseLayers[id];
+ <span class="commentJS">/* If - obj - remains undefined (no element existed with the
+ given - id -) try searching the indexed members of
+ - baseLayers - to see if any of their layers collections
+ contain the element with the corresponding - id:
+ */</span>
+ if(!obj){ <span class="commentJS">//Element not found</span>
+ <span class="commentJS">/* Loop through the indexed members of - baseLayers: */</span>
+ for(var c = 0;c &lt; baseLayers.length;c++){
+ if((baseLayers[c])&amp;&amp; <span class="commentJS">//Object at index - c.</span>
+ (baseLayers[c].document)&amp;&amp; <span class="commentJS">//It has a - document.</span>
+ <span class="commentJS">/* And a layers collection on that document: */</span>
+ (baseLayers[c].document.layers)){
+ <span class="commentJS">/* Recursively call this function passing the - id - as
+ the first parameter and the layers collection from
+ within the document found on the layer at index - c
+ - in - baseLayers - as the second parameter and
+ assign the result to the local variable - obj:
+ */</span>
+ obj=getElementWithId(id,baseLayers[c].document.layers);
+ <span class="commentJS">/* If - obj - is now not null then we have found the
+ required element and can break out of the - for -
+ loop:
+ */</span>
+ if(obj)break;
+ }
+ }
+ }
+ <span class="commentJS">/* If - obj - will type-convert to boolean true (it is not null
+ or undefined) return it, else return null:
+ */</span>
+ return obj||null;
+ }
+}else{
+ <span class="commentJS">/* No appropriate element retrieval mechanism exists on
+ this browser. So assign this function as a safe dummy.
+ Values returned form calls to getElementWithId probably
+ should be tested to ensure that they are non-null prior
+ to use anyway so this branch always returns null:-
+ */</span>
+ getElementWithId = function(id){
+ return null;
+ }
+}
+
+<span class="commentJS">/*
+Usage:-
+
+var elRef = getElementWithId(&quot;ID_string&quot;);
+if(elRef){
+ ... //element was found
+}else{
+ ... //element could not be found.
+}
+*/</span>
+</pre>
+
+<p id="bdGEID_4">
+The feature detecting tests are performed once as the page loads and
+one of many function expressions assigned to the
+<code>getElementWithId</code> global variable as a result. The
+assigned function is the one most capable of retrieving the required
+element on the browser in use but it is still necessary to check that
+the returned value in not <code>null</code> and plan for the
+possibility of failure in the element retrieval process. It is
+guaranteed to fail on any browser that does not implement at least one
+of the element retrieval mechanisms used as the default function just
+returns <code>null</code>.
+</p>
+
+<p id="bdGEID_5">
+It may not be sufficient to provide a function that does the best job
+of element retrieval that can be done on the browser in use. Other
+scripts, or parts of the script, may need to know how successful their
+attempts to retrieve elements are likely to be. The
+<code>getElementWithId</code> version that uses
+<code>document.layers</code> cannot retrieve elements that are not <span class="initialism" title="Cascading Style Sheet"><abbr title="Cascading Style Sheet">CSS</abbr></span>
+positioned and that may not be good enough for some scripts, while it
+may not matter to others. The <code>document.getElementById</code> and
+<code>document.all</code> versions should be able to retrieve any
+element given its <code>ID</code>. An opting would be to set a couple
+of boolean flags to indicate how successful element retrieval can be
+expected to be. Defaulting the flags to <code>false</code> and setting
+them to <code>true</code> in the branches that assign the various
+function expressions. Then if other code is interested in what can be
+expected from the <code>getElementWithId</code> function, say in order
+to decide how to configure, or default itself, it can check the
+pertinent flag.
+</p>
+
+<pre id="bdGEID_ex3">
+var getElementWithId;
+var canGetAnyElement = false; <span class="commentJS">//default any element flag</span>
+var canGetCSSPositionedElements = false; <span class="commentJS">//default <span class="initialism" title="Cascading Style Sheet"><abbr title="Cascading Style Sheet">CSS</abbr></span> positioned flag</span>
+if(document.getElementById){
+ canGetAnyElement = true; <span class="commentJS">//set any element flag to true</span>
+ canGetCSSPositionedElements = true; <span class="commentJS">//set <span class="initialism" title="Cascading Style Sheet"><abbr title="Cascading Style Sheet">CSS</abbr></span> positioned flag true</span>
+ getElementWithId = ...
+}else if(document.all){
+ canGetAnyElement = true; <span class="commentJS">//set any element flag to true</span>
+ canGetCSSPositionedElements = true; <span class="commentJS">//set <span class="initialism" title="Cascading Style Sheet"><abbr title="Cascading Style Sheet">CSS</abbr></span> positioned flag true</span>
+ getElementWithId = ...
+}else if(document.layers){
+ canGetCSSPositionedElements = true; <span class="commentJS">//set <span class="initialism" title="Cascading Style Sheet"><abbr title="Cascading Style Sheet">CSS</abbr></span> positioned flag true</span>
+ <span class="commentJS">/* The - canGetAnyElement - flag is not set in this branch because
+ the document.layers collection does not make *all* elements
+ available.
+ */</span>
+ getElementWithId = ...
+}else{
+ <span class="commentJS">/* Neither flag is set when the dummy function is assigned because
+ it is guaranteed not to be able to retrieve any elements:
+ */</span>
+ getElementWithId = function(id){
+ return null;
+ }
+}
+...
+if(canGetCSSPositionedElements){
+ <span class="commentJS">/* Expect to be able to retrieve <span class="initialism" title="Cascading Style Sheet"><abbr title="Cascading Style Sheet">CSS</abbr></span> positioned elements.
+ */</span>
+ ...
+ if(canGetAnyElement){
+ <span class="commentJS">/* Expect to also be able to retrieve any other elements that
+ have an ID attribute.
+ */</span>
+ ...
+ }
+}
+</pre>
+
+<p id="bdGEID_6">
+The flags do not directly reflect which feature is going to be used
+for element retrieval, instead they reflect what can be expected from
+the <code>getElementWithId</code> function on the current browser.
+Allowing a script that requires a particular level of performance
+(say the retrieval of any element) to determine whether it will have
+that facility but without denying the facility from a script with a
+less demanding requirement.
+</p>
+
+<h3 id="bdScroll">Example 2: Scroll Values</h3>
+
+<p id="bdScroll_1">
+Another common task that needs to be approached differently on
+different browsers is the retrieval of the extent to which the user
+has scrolled a web page. The majority of browsers provide properties
+of the global object called <code>pageXOffset</code> and
+<code>pageYOffset</code>, which hold the relevant values. Some make the
+equivalent browsers available as scrollLeft and scrollTop properties on
+the &quot;root&quot; element (either in addition to the
+<code>pageX/YOffset</code> properties or instead of them). The task is
+complicated further by the fact that which element is the
+&quot;root&quot; element depends on various factors, it was always the
+<code>document.body</code> element in the past but newer (<span class="initialism" title="Cascading Style Sheet"><abbr title="Cascading Style Sheet">CSS</abbr></span>)
+standards compliant browsers (and browsers that can operate in various
+modes, including standards compliant mode) make the
+<code>document.documentElement</code> the root element. Then there may
+be browsers that do not make the scrolling values available at all.
+</p>
+
+<p id="bdScroll_2">
+Because the <code>pageXOffset</code> and <code>pageYOffset</code>
+properties are implemented on the largest number of browsers, and their
+use avoids the need to worry about the &quot;root&quot; element, they
+are the preferred values to use. In there absence the problem moves on
+to identifying the &quot;root&quot; element, which is made easier by
+the browsers that understand standards compliant mode and provide a
+<code>document.compatMode</code> string property to announce which mode
+they are in. If the string property is missing or the value of that
+string is other than <code>&quot;CSS1Compat&quot;</code> then it is the
+<code>document.body</code> object that needs to be read for the
+scrolling values, else the <code>document.documentElement</code> should
+be read. Testing for the presence of any of the scroll values
+themselves needs to done with a <code>typeof</code> test because they
+are numeric values and if implemented but set to zero a type-converting
+test would return <code>false</code> but that would not be an indicator
+of their absence.
+</p>
+
+<p id="bdScroll_3">
+The following is an example that employs feature detection to decide
+which scroll values to read:-
+</p>
+
+<pre id="bdScroll_ex1">
+<span class="commentJS">/* The - getPageScroll - global variable is assigned a reference to a
+ function and when that function is called initially it configures
+ the script to read the correct values, if available, and then
+ returns a reference to the object - interface - which provides
+ methods that retrieve the scroll values. Subsequent invocations of
+ the getPageScroll function do not repeat the configuration, they
+ just return a reference to the same interface object. Because the
+ configuration stage may need to check whether the document.body
+ element exists the function cannot be called until the browser has
+ parsed the opening body tag as prior to that point there is no
+ document.body element.
+
+ Usage:-
+ var scrollInterface = getPageScroll();
+ var scrollX = scrollInterface.getScrollX();
+ var scrollY = scrollInterface.getScrollY();
+
+ The interface methods return NaN if the browser provides no method
+ of reading the scroll values. A returned NaN value can be tested for
+ with the - isNaN - global function, but it should not be necessary
+ to perform the isNaN test on more than the first retrieval because
+ if the returned value is NaN it will always be NaN and if it is not
+ it should never be.
+
+ if(isNaN(scrollX)){
+ //No scroll value retrieval mechanism was available on this browser
+ }
+
+ (* The script performs an inline execution of a function expression
+ which returns the function object that is assigned to the -
+ getPageScroll - global variable. This produces a closure that
+ preserves the local variables of the executed function expression,
+ allowing the execution context of the function expression to provide
+ a repository for the configuration results, keeping them out of the
+ global namespace. The format is:-
+
+ v--- Anonymous function expression --v
+ var variable = (function(){ ...; return returnValue; })();
+ Inline execution of the function expression ----^^
+
+ The value returned by the inline execution of the anonymous function
+ expression is assigned to the variable. If that returned value is a
+ reference to an inner function object then the assignment will form
+ a closure.)
+*/</span>
+var getPageScroll = (function(){
+ <span class="commentJS">/* The local variable &quot;global&quot; is assigned the value - this -
+ because the function expression is executing in the global
+ context and - this - refers to the global object in that
+ context. The global object is usually the - window - object on
+ web browsers but this local variable is going to be used in the
+ configuration tests for convenience:
+ */</span>
+ var global = this;
+ <span class="commentJS">/* notSetUp - Is a flag to indicate when the script has done the
+ setup configuration:
+ */</span>
+ var notSetUp = true;
+ <span class="commentJS">/* readScroll - Is initially a dummy object that is used to return
+ the NaN values whenever no functional scroll value retrieval
+ mechanism is available on the browser. It is assigned a
+ reference to the object from which the scroll values can be read
+ if the feature detection determines that to be possible:
+ */</span>
+ var readScroll = {scrollLeft:NaN,scrollTop:NaN};
+ <span class="commentJS">/* Using the local variables - readScrollX - and readScrollY - to
+ hold the property names allows the same functions to read both
+ the pageX/YOffset properties of the global object and the
+ scrollTop/Left properties of the &quot;root&quot; element by assigning
+ different values to the variables. These are the defaults:
+ */</span>
+ var readScrollX = 'scrollLeft';
+ var readScrollY = 'scrollTop';
+ <span class="commentJS">/* The - itrface - local variable is assigned a reference to an
+ object and it is this object that is returned whenever
+ getPageScroll() is called. The object has two properties,
+ getScrollX and getScrollY, which are assigned the values of two
+ anonymous function expressions. These functions are inner
+ functions and as a result have access to the local variables of
+ the function that contains them (the anonymous function
+ expression that is executed inline in order to assign value to
+ the getPageScroll global variable). The use a square bracket
+ property accessor to read a value of whatever object has been
+ assigned to the variable - readScroll - with a property name
+ that corresponds to the value assigned to whichever of the
+ variables - readScrollX - or - readScrollY - are employed,
+ allows the functions to use the simplest code poible to provide
+ values for all of the possible permutations resting from the
+ feature detection derived configuration:
+ */</span>
+ var itrface = {
+ getScrollX:function(){
+ return readScroll[readScrollX];
+ },
+ getScrollY:function(){
+ return readScroll[readScrollY];
+ }
+ };
+ <span class="commentJS">/* The - setUp - inner function is called to perform the feature
+ detection and configure the variables that will be employed in
+ reading the correct scroll values. It sets the - notSetUp - flag
+ to false once it has been executed so that configuration only
+ happens the first time that a request for the interface object
+ is made:
+ */</span>
+ function setUp(){
+ <span class="commentJS">/* As the paeX/YOffset properties are the preferred values to
+ use they are tested for first. They are not both tested
+ because if one exists the other can be assumed to exist for
+ symmetry. The testing method is a - typeof - test to see if
+ the value is a number. A type-converting test cannot be used
+ because the number zero would result in boolean false and a
+ pageXOffset value will be zero if the page has not been
+ scrolled:
+ */</span>
+ if(typeof global.pageXOffset == 'number'){
+ <span class="commentJS">/* If pageXOffset is a number then the value of the -
+ global - variable (assigned a reference to the global
+ object earlier) is assigned to the - readScroll -
+ variable and the strings &quot;pageXOffset&quot; and &quot;pageYOffset&quot;
+ are assigned to the - readScrollX - and - readScrollY -
+ variables so they will be the property names used to
+ access the - readScroll- (now the global) object.
+ */</span>
+ readScroll = global;
+ readScrollY = 'pageYOffset';
+ readScrollX = 'pageXOffset';
+ }else{
+ <span class="commentJS">/* If pageXOffset is undefined it is time to find out which
+ object is the &quot;root&quot; element. First, does the browser
+ have a - document.compatMode - string, if it does then
+ is its value &quot;BackCompat&quot;, &quot;QuirksMode&quot; or &quot;CSS1Compat&quot;.
+ Instead of comparing the string directly it is searched
+ for the substring &quot;<span class="initialism" title="Cascading Style Sheet"><abbr title="Cascading Style Sheet">CSS</abbr></span>&quot; which might make the script more
+ robust in the face of possible future &quot;CSSnCompat&quot;
+ modes, which are unlikely to demand that the &quot;root&quot;
+ element is moved again.
+
+ The tests also verifies that there is a -
+ document.documentElement - to read and that its
+ - scrollLeft - property is a number:
+ */</span>
+ if((typeof document.compatMode == 'string')&amp;&amp;
+ (document.compatMode.indexOf('CSS') &gt;= 0)&amp;&amp;
+ (document.documentElement)&amp;&amp;
+ (typeof document.documentElement.scrollLeft=='number')){
+ <span class="commentJS">/* The - readScrollX - and - readScrollY - variables
+ are already defaulted to the required strings so it
+ is only necessary to assign a reference to the -
+ document.documentElement - to the - readScroll -
+ variable:
+ */</span>
+ readScroll = document.documentElement;
+ <span class="commentJS">/* If the browser is not in the appropriate mode the scroll
+ values should be read from the document.body - element,
+ assuming it exists on this browser and that the
+ - scrollLeft - property is a number:
+ */</span>
+ }else if((document.body)&amp;&amp;
+ (typeof document.body.scrollLeft == 'number')){
+ <span class="commentJS">/* The - readScrollX - and - readScrollY - variables
+ are already defaulted to the required strings so it
+ is only necessary to assign a reference to the -
+ document.body - to the - readScroll - variable:
+ */</span>
+ readScroll = document.body;
+ }
+ <span class="commentJS">/* No other scroll value reading options exist so if -
+ readScroll - has not been assigned a new value by this
+ point it will remain a reference to the object with the
+ NaN value properties.
+ */</span>
+ }
+ notSetUp = false; <span class="commentJS">//No need to repeat configuration.</span>
+ }
+ <span class="commentJS">/* The inline execution of the anonymous function expression
+ returns with the following statement. It returns an inner
+ function expression and it is that function that will be called
+ when getPageScroll() is executed. Doing this forms a closure,
+ preserving all of the local variables and functions defined
+ within the executed anonymous function expression. Calling that
+ returned function as - getPageScroll() - executes the setUp
+ function, but only if it has not already been called, and
+ returns a reference to the - itrface - object.
+ */</span>
+ return (function(){
+ if(notSetUp){ <span class="commentJS">//If the - notSetUp - variable is still true.</span>
+ setUp(); <span class="commentJS">//Execute the - setUp - function.</span>
+ }
+ return itrface; <span class="commentJS">//returns a reference to - itrface</span>
+ });
+})(); <span class="commentJS">//inline-execution of anonymous function expression, one-off!</span>
+</pre>
+
+<p id="bdScroll_4">
+The effect of this code is to match the browser's ability to provide
+the scrolling information with a script's desire to read it through a
+simple and efficient interface that acts based on the results of
+featured detecting tests that it applies only once, and if the browser
+does not support any methods of reading the scroll values the return
+values form the interface method indicate that fact by being NaN. It
+does not matter that Netscape 4 will be reading the global
+<code>pageX/YOffset</code> properties, that IE 4 will read the
+<code>scrollTop/Left</code> properties from <code>document.body</code>
+or that IE 6 will read those values from one of two possible objects
+based on the <code>document.compatMode</code> value. What is important
+is that if unknown browser XYZ provides any of those mechanisms for
+reporting the scroll values the script is going to be able to use them,
+without ever knowing (or caring) that it is browser XYZ that it is
+executing on.
+</p>
+
+<h3 id="bdReplace">Example 3: String.prototype.replace</h3>
+
+<p id="bdReplace_1">
+Feature detecting is not restricted to features of the DOM, it can be
+extended to include features of the javascript language implementation.
+For example the <code>String.prototype.replace</code> function in later
+language versions will accept a function reference as its second
+argument, while earlier versions only accept a string in that context.
+Code that wants to use the function argument facility of the
+<code>replace</code> method will fail badly if it is not supported on
+the browser.
+</p>
+
+<p id="bdReplace_2">
+As usual, a feature-detecting test for the implementation's ability to
+support function arguments with the <code>replace</code> method has to
+be a direct test on that feature. The following example test takes
+advantage of the fact that a browser that only supports the string
+argument version of <code>replace</code> will type-convert a function
+reference used in that context into a string. The <code>replace</code>
+method uses a Regular Expression (its first argument) to
+identify parts of a string and then replaces them with a string that is
+provided as its second argument. If the second argument is a function,
+and the browser supports the function argument, that function is called
+and its return value replaces the identified parts of the string.
+</p>
+
+<p id="bdReplace_3">
+By providing a function expression that returns an empty string as its
+second argument and a Regular Expression that identifies the entire
+original string as the first argument, the operation of the
+<code>replace</code> method will result in an empty string if the
+function argument is supported. But if only string arguments are
+supported then the function will be type-converted into a string and
+that string will not be an empty string so the result of the
+evaluation of the <code>replace</code> method will not be an empty
+string. Applying a NOT (<code>!</code>) operation to the resulting
+string type-converts the empty string into a boolean value, inverts
+it and returns <code>true</code>, the non-empty string would result
+in <code>false</code>.
+</p>
+
+<pre id="bdReplace_ex1">
+<span class="commentJS">/* The original string is the one letter string literal &quot;a&quot;. The
+ Regular Expression /a/ identifies that entire string, so it is the
+ entire original string that will be replaced. The second argument is
+ the function expression - function(){return '';} -, so the entire
+ original string will be replaced with an empty string if the
+ function expression is executed. If it is instead type-converted
+ into a string that string will not be an empty string. The NOT (!)
+ operation type-converts its operand to boolean and then inverts it
+ so the results of the test is boolean true if function references
+ are supported in the second argument for the - replace - method, and
+ false when not supported:
+*/</span>
+if(!('a'.replace(/a/, (function(){return '';})))){
+ ... <span class="commentJS">//function references OK.</span>
+}else{
+ ... <span class="commentJS">//no function references with replace.</span>
+}
+</pre>
+
+<p id="bdReplace_4">
+The common thread with feature detecting is that it is the code that is
+going to use the features, and the nature of those features, that
+defines how support for the required feature needs to be tested. Once
+you get used to the idea it starts to become obvious which tests need
+to be applied to verify a browser's support for a feature, and then it
+is time to work on the efficient application of feature detection.
+</p>
+
+<h2 id="bdDesPb">The Javascript Design Problem</h2>
+
+<p id="bdDesPb_1">
+Javascript as a language is not that complex, it may have its quirks
+but it can be defined entirely in the 173 pages of the ECMA
+specification (3rd edition). The challenge of authoring javascript
+comes form the diversity of execution environments. When authoring for
+the Internet nothing is known about the receiving software in advance,
+and even when that software is a web browser that will execute
+javascript, there is still a spectrum of possible DOM implementations
+to contend with.
+</p>
+
+<p id="bdDesPb_2">
+The combination of the facts that it is impossible to determine which
+browser is executing the script, and that it is impossible to be
+familiar with all browser DOMs can be rendered insignificant by using
+feature detection to match code execution with any browser's ability to
+support it. But there is still going to be a diversity of
+outcomes, ranging from total failure to execute any scripts (on
+browsers that do not support javascript, or have it disabled) to full
+successful execution on the most capable javascript enabled browsers.
+</p>
+
+<p id="bdDesPb_3">
+The challenge when designing scripts is to cope with all of the
+possibilities in a way that makes sense for everyone. As those
+possibilities will always include browsers incapable of executing
+javascript at all, the starting point must be pages based on (valid)
+<span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> that contain all of the required content, allow the necessary
+navigation and are as functional as they purport to be (possibly with
+the backing of server-side scripting, which does not have any of the
+problems of client side scripting). On top of that reliable foundation
+it is possible to layer the scripts. Feature detecting and adding
+scripted enhancements when the browser is capable of supporting them,
+cleanly degrading to the underlying and reliable <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> when it is not.
+</p>
+
+<p id="bdDesPb_4">
+A well designed script, implementing a suitable strategy, can enhance
+the underlying <span class="initialism" title="HyperText Mark-up Language"><abbr title="HyperText Mark-up Language">HTML</abbr></span> page, exploiting the browser's capabilities to the
+maximum extent possible and still exhibit planed behaviour in the
+absence of any (or all) desired features and degrade cleanly where
+necessary. Nobody should either consider themselves a skilled Internet
+javascript author, or deprecate javascript as a language and/or browser
+scripting as a task, until they have demonstrated an ability to write
+a non-trivial script that achieves that goal.
+</p>
+</body>
+</html>
/trunk/cljs/faq_notes/not_browser_detect.html
Property changes:
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property