Nickolay Ponomarev wrote:
In Mozilla source you can often see declarations like this:
var obj = {
//...
method1: function obj_method1() {
}
};
..which creates a named function 'obj_method1' and assigns it to
obj.method1.
Unfortunately the well-known bug in JScript makes this a potentially very
bad idea. To illustrate:-
<html>
<head>
<title>Untitled Document</title>
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1">
</head>
<body>
<script type="text/javascript">
var f;
var test = 'Global';
document.write(aFunction +'<br>');
/*
Outputs:-
function aFunction(){return test;}
- and that is a bit odd, as the function expression with the optional
Identifier has not yet been evaluated. You might expect that result
when there was a FunctionDeclaration further down the code (as that
would result in the creation of a function object during variable
instantiation).
*/
with({test:'Scope Chain'}){
f = {
x:function aFunction(){return test;}
};
}
document.write(f.x +'<br>');
/*
Outputs:-
function aFunction(){return test;}
- so the - x - property of - f - refers to a function the - toString -
method of which appears to be returning the function expression with
optional Identifier.
*/
document.write(aFunction +'<br>');
/*
Outputs:-
function aFunction(){return test;}
- so a global - aFunction - refers to a function the - toString -
method of which appears to be returning the function expression with
optional Identifier. This may suggest a leaking of the Identifier -
aFunction - into the containing scope, but the next tests demonstrate
that that is not the case here.
*/
document.write((aFunction == f.x)+'<br>');
/*
Outputs:-
false
The function object referred to by a global - aFunction - is _not_ the
same function object as referred to by the - x - property of - f -.
There appear to be _two_ function objects here.
*/
/*
These tests demonstrate one of the consequences of this JScript bug.
When called the function objects attempt to resolve the Identifier -
test -. They do that against there respective scope chains and each's
Variable object does not have a - test - property so if it is resolved
it will not be as a property of the Variable object. If they come up
with different result there must be two distinct functions objects,
with two different scope chains.
There are two candidate - test - properties, a global - test -
property with the value "Global", and a - test - property on the
object added to the scope chain of function created with the
fucntion expression through the use of a - with - statement.
*/
document.write(f.x()+'<br>');
/*
Outputs:-
Scope Chain
- so the function object referred to by the - x - property of - f -
appear to be the result of evaluating a function expression within
an - with - statement, as the object added to the execution
context's scope chain with the - with - statement is on the scope
chain of the resulting function object (as expected).
*/
document.write(aFunction()+'<br>');
/*
Outputs:-
Global
- so the function object referred to by - aFunction - does not
have any object with a - test - property above the global object.
*/
</script>
</body>
</html>
The most comprehensive hypothesise that explains this behaviour is that
when JScript looks for FunctionDeclarations it uses a rather crude method
(probably for speed) but unfortunately it sees all FunctionExpressions
with optional Identifiers as FucntionDeclarations, but does so in a way
that does not prevent them from later being evaluated as
FunctionExpressions. The result is that every FunctionExpression with
optional Identifier causes a function object to be created during
variable instantiation (and assigned to a property of the Variable object
under a name that corresponds with the Identifier, and then, if
evaluated, a second function object is created. These two function
objects contain the same body code, but they differ in all the ways that
would be expected as a result of their differing contexts of creation.
Just to throw a little more confusion into the picture there is another
bug in JScript's handling of FunctionExpressions with optional
Identifiers. While the optional Identifier should result in an object
being added to the scope chain prior to the creation of the function
object, and a property added to that object with a name that corresponds
with the Identifier, and eventually a reference to the function object
assigned to that property. This does not happen in JScript, and so if the
code in the function body attempts to resolve the Identifier that was
used as its name it will be resolved as the function object resulting
from JScript treating the FunctionExpression as a FunctionDeclaration.
That means that if code in the function object that did result form the
evaluation of the function expression attempts to call itself using its
'name' it will actually be calling the other function object (which may
have another scope chain).
Giving names to functions in such a way is useful for
debugging:
* you can print sensible names in stack traces
* I believe Venkman uses function names when printing
profiling data.
* When you want to add logging to a function that takes
a function as a parameter.
and so on.
<snip>
That may help in debugging JavaScript(tm), in JScript it is going to be a
possible cause of extremely difficult to track down bug. The upshot of
which is that it is not that good an idea when doing cross browser work
(so pretty much anything commercial) unless the programmer had a very
good idea of what is going on in both ECMA conforming environments and
those with common bugs (JScript). And when that level of understanding
has been achieved other debugging strategies will have been recognised to
negate any benefits of giving names to FunctionExpressions.
Richard.