function identifier vs. arguments.callee

V

VK

I was getting this effect N times but each time I was in rush to just
make it work, and later I coudn't recall anymore what was the original
state I was working around. This time I nailed the bastard so posting
it before I forgot again...

By taking this minimum code:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<title>Demo</title>
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1">
<script type="text/javascript">

// 1)
(function refByCallee() {
arguments.callee.foobar = 'foobar';
})();

// 2)
(function refByName() {
refByName.foobar = 'foobar';
})();

if (typeof refByCallee != 'undefined') {
alert(typeof refByCallee.foobar); // undefined
alert(typeof refByName.foobar); // string
}
</script>
</head>
<body>
<h1>Demo</h1>
</body>
</html>

There are two issues here: the one is well-known and another I what I
want to ask about.

1) The known issue is the difference of how JavaScript and JScript are
treating function declarations within expression. In JScript it still
leads to a function reference added to the global namespace, just as
without any parenthesis.
This way on IE after executing 1) and 2) we have two new global named
functions while on other engines not.

2) What I'm not sure is how to explain that IE obviously makes
difference here between arguments.callee and literal name. While
literal name acts as expected - see 2) - arguments.callee points to
some other object instance disappearing right after the execution.

Any insides?
 
J

Jonas Raoni

VK escreveu:
I was getting this effect N times but each time I was in rush to just
make it work, and later I coudn't recall anymore what was the original
state I was working around. This time I nailed the bastard so posting
it before I forgot again...

By taking this minimum code:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<title>Demo</title>
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1">
<script type="text/javascript">

// 1)
(function refByCallee() {
arguments.callee.foobar = 'foobar';
})();
if (typeof refByCallee != 'undefined') {
alert(typeof refByCallee.foobar); // undefined
alert(typeof refByName.foobar); // string
}

The bellow lines show you what happens (the "namedFunction" isn't the
same object that is returned by the function declaration).

var f = function namedFunction(){
//alert(namedFunction === arguments.callee);
//alert(f === arguments.callee);
arguments.callee.property = '[I exist]';
};
namedFunction(); //using namedFunction as callee
alert(namedFunction.property + "\n" + f.property);

f(); //using f as callee
alert(namedFunction.property + "\n" + f.property);
 
R

Richard Cornford

VK said:
I was getting this effect N times but each time I was in rush
to just make it work, and later I coudn't recall anymore what
was the original state I was working around.

And you wonder why nobody takes you seriously when you label yourself a
"programmer"?
This time I nailed the bastard so posting
it before I forgot again...

Well, there is no hope that you could analyse this for yourself.
By taking this minimum code:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<title>Demo</title>
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1">

"Minimum code" does not need a META element.
<script type="text/javascript">

// 1)
(function refByCallee() {
arguments.callee.foobar = 'foobar';
})();

// 2)
(function refByName() {
refByName.foobar = 'foobar';
})();

if (typeof refByCallee != 'undefined') {
alert(typeof refByCallee.foobar); // undefined
alert(typeof refByName.foobar); // string
}
</script>
</head>
<body>
<h1>Demo</h1>
</body>
</html>

There are two issues here: the one is well-known and
another I what I want to ask about.

1) The known issue is the difference of how JavaScript
and JScript are treating function declarations within
expression.

There is no sense in "function declarations within expression". Programs
and function bodies are made up of FunctionDeclarations and Statements
(two mutually exclusive constructs), Expressions are components of
Statements. The code above only features FunctionExpressions with
optional Identifiers.
In JScript it still leads to a function reference added
to the global namespace,

IE erroneously adds named properties referring to function objects to
the Variable object for the execution context in which the
FunctionExpressions with optional Identifiers appears. That is only the
global object in the global execution context.
just as without any parenthesis.

Without the parenthesise the constructs are unambiguously
FunctionDeclaration (to every ECMAScript engine).
This way on IE after executing 1) and 2) we have two
new global named functions while on other engines not.

On IE you actually have two named properties of the Variable object
referring to function objects _before_ the execution of 1) and 2). And
this fact is the biggest clue as to what IE is really doing when it
misinterprets this code.
2) What I'm not sure is how to explain that IE obviously
makes difference here between arguments.callee and literal
name.

You mean a difference between the object referred to by -
arguments.callee - and the object referred to by the Identifier.
While literal name acts as expected - see 2)

It only acts as expected if you appreciate the bug in IE. The
expectation derived from the language specification is that the
Identifier used outside of the function bodies should not resolve into
references to function objects, and inside the function bodies they
should refer to the same object as - arguments.callee -. It is the
difference between the formal specification that Microsoft assert
JScript follows and the behaviour of JScript that allows this to be
labelled a bug.
- arguments.callee points to some other object instance
disappearing right after the execution.

The - arguments.callee - reference should refer to the function object
that is being executed, and it does. As that function object results
form the inline execution of a FunctionExpression and no reference to
that function object is assigned to any property of any other object in
the system you should expect that object to 'disappear' following its
execution.

Apart from failing to test for the existence of the properties of the
Variable object prior to the execution of the FunctionExpressions (and
so not noticing that they do exist, and refer to function objects, at
that point), you have not verified that, for example, - refByCallee -
and - arguemnts.callee - refer to the same object. The tests is simple:-

alert('(callee === refByCallee) '+(arguments.callee === refByCallee));

- and with:-

(function fn() {
alert('(callee === fn) '+(arguments.callee === fn));
arguments.callee.foobar = 'foobar';
})();

- the result is false. The object referred to by the Identifier - fn -
is not the same object as referred to by - arguments.callee - inside the
executing function object.

Meanwhile, with:-

fn();

(function fn() {
alert('(callee === fn) '+(arguments.callee === fn));
arguments.callee.foobar = 'foobar';
})();

fn();

- the alerts are true, false and true (in that order). Prior to the
evaluation of the FunctionExpression an - fn - function exists, can be
called and is the object referred to by - arguments.callee - when it is
executing. When the FunctionExpression is executed - argument.callee -
does not refer to the - fn - function, and after the execution of the
FunctionExpression a second call to the - fn - function again results in
the execution of a function object that's - arguments.callee - refers to
the - fn - function.

The explanation for this is simply that there are two function objects
involved; a function object that is referred to by the property of the
Variable object and comes into existence prior to the execution of any
code for the execution context, and a second function object that comes
into existence as a result of the evaluation of the FunctionExpression.

The function object coming into existence with the evaluation of the
FunctionExpression is what is supposed to happen (the handling of the
optional Identifier is still wrong on IE, but then optional Identifiers
are not really expected to be used with FunctionExpressions). So it is
the creation of the first function object that represents the
manifestation of the bug in IE. The fact that these functions, and
corresponding properties of the Variable object, come into existence
prior to the execution of any code for the execution context suggests
that the fault is in the variable instantiation stage of execution.
Specifically, that at the point of scanning for function declarations IE
is using criteria for identifying Function Declarations that are
considerably more crude than the formal syntax rules for a
FunctionDeclaration. That is, it is looking for the - function keyword
followed by an Identifier followed by a matching set of braces and
taking any occurrences of that, regardless of context, as a Function
Declaration. And so finding, and acting upon, considerably more
FunctionDeclarations than exist in the actual code.

This probably represents an attempt at an optimisation for speed. It has
been observed that IE is the fastest browser at parsing javascript
source (by the fact that its - eval - function and - Function -
constructor out perform all other environments) and being a bit lax on
the syntax rules may be key to this.

The consequences of this bug are largely insignificant as nobody should
be writing code with the expectation that the optional Identifier in a
FunctionExpression should be available outside of the resulting
function, and so not be attempting to refer to that function in that
way. Your own code, for example, is stupidly designed. If you wanted to
refer to named global functions (to use them as a vehicle for passing
data about) then it would be trivial (and more obvious) to have the
function objects created globally with FunctionDeclarations. If stupidly
obtuse code is written then it likely will fall over implementation
bugs.

Richard.
 
V

VK

Jonas said:
The bellow lines show you what happens (the "namedFunction" isn't the
same object that is returned by the function declaration).

var f = function namedFunction(){
//alert(namedFunction === arguments.callee);
//alert(f === arguments.callee);
arguments.callee.property = '[I exist]';
};
namedFunction(); //using namedFunction as callee
alert(namedFunction.property + "\n" + f.property);

f(); //using f as callee
alert(namedFunction.property + "\n" + f.property);

Yes, I knew it already - but still thank you for answering. My question
was what kind of object arguments.callee is in this case and what
mechanics is behind.
 
V

VK

Richard said:
"Minimum code" does not need a META element.

Not for a HTML source and especially not for a HTML with a script
sample - unless one has a guarantee that the sample will be always
first uploaded to a properly configured server setting charset in
Content-Type header and only then viewed from that server.

Otherwise IE users with View > Encoding > Auto-Select activated may hit
the "Korean issue" while trying to execute the sample with the most
strange results to expect. The results will be especially "visually
impressive" if the current IE has Hangul (Korean phonemic alphabet)
package installed :)

Try this for instance on IE with Auto-Select activated:

<html>
<head>
<title>Demo</title>
</head>
<body>
<h1>+10-</h1>
<script type="text/javascript">
var foo = "a" + "A";
alert(foo);
</script>
</body>
</html>

This way rather than being dependant on circumstances or checking each
source for the "Korean issue vulnerability" one should *always* set
META with matching charset. For the majority of simple demos ISO-8859-1
does the needed trick.

At the same time the existing standards do not require to place
META-EQUIV with Content-Type on the page. This way the brave people are
welcome to disregard this advice. They are even welcome do not set
Content-Type anywhere at all because current RFCs specify default
charset for both HTML and XML. I'm personally glad to see as many of
such "standard informed" people as possible. This people is the
quickest and easiest source of money for any help desk including ours
:)
 
V

VK

Richard said:
There is no sense in "function declarations within expression". Programs
and function bodies are made up of FunctionDeclarations and Statements
(two mutually exclusive constructs), Expressions are components of
Statements. The code above only features FunctionExpressions with
optional Identifiers.

Thanks for your explanations which are snipped in this reply but which
are gracefully read.

In relevance to "bug" vs "behavior specific" the matter doesn't seem as
straightforward as you stated IMHO. The question is whether function
declaration
function something() {
}
becomes function statement just because you have surrounded it by
parenthesis:
(function something() {
})

?

ECMA and Gecko seems thinking yes. Microsoft seems thinking no, and
this point has some merit IMHO. Function object cannot be in the
left-hand side of an expression. So in case like
(function something() {
})();
we either have a syntaxically incorrect statement or
FunctionDeclaration.

You may shot now if you want to :) - I just expressed my worthless
opinion :)
 
R

Richard Cornford

VK said:
Thanks for your explanations which are snipped in this reply
but which are gracefully read.

Evidently much of it went straight over your head, which is not
unexpected.
In relevance to "bug" vs "behavior specific" the matter
doesn't seem as straightforward as you stated IMHO.

Your opinions are, as always, worthless. In this case you ignorance of
the syntax rules for javascript, the related concepts, and your
consequent inability to understand my explanation of the pertinent
details, is the reason for that.
The question is whether
function declaration
function something() {
}
becomes function statement

It is a FunctionExpression. The syntactic units relating to functions
are FunctionDeclaration and FunctionExpression. Neither are Statements.
FunctionDeclarations and Statements are the two types of component that
make up Programs and function bodies, and so are mutually exclusive.
Statements may contain Expressions and so may contain Function
Expressions, though the syntax rules explicitly forbid the possibility
of any Statement consisting of only a Function Expression (by excluding
the function keyword from the possible tokens that may commence an
ExpressionStatement).
just because you have surrounded it by
parenthesis:
(function something() {
})

?

Surrounding the FunctionExpression with parenthesise does exactly that,
as the only construct that may commence with an opening parenthesis
token is an ExpressionStatement, the only Expression that may commence
with an opening parenthesis is the "Grouping operator"
PrimaryExpression, and the "Grouping operator" PrimaryExpression is only
allowed to contain an Expression.

Even if the opening parenthesis do not commence the Statement, that is,
if they follow a MemberExpression and so would be interpreted as an
Arguments List (forming a CallExpression) that Arguments List is still a
list of zero or more Expressions.

And so if you wrap parentheses around - function Identifier<opt> (
FormalParameterList<opt> ) { FunctionBody } - you do guarantee that what
you have just wrapped in parenthesise is a FunctionExpression (and so
part of a Statement) and absolute not a FunctionDeclaration (as
Statements and Function Declarations are mutually exclusive).
ECMA and Gecko seems thinking yes. Microsoft seems
thinking no,

If Microsoft do not think that construct is a FunctionExpression why is
JScript creating a new function object when it evaluates the Expression?
and this point has some merit IMHO.

Your opinions are, as always, worthless.
Function object cannot be in the
left-hand side of an expression.

Nonsense. Values that represent references to function objects (which is
what a parenthesised FunctionExpression evaluates as) are always the
left hand side of CallExpressions (that is, every successful
function/method call that is ever executed). It is your habitual making
ridiculous statements like that helps renders your opinions worthless.
So in case like
(function something() {
})();
we either have a syntaxically incorrect statement or
FunctionDeclaration.

It is a syntactically correct CallExpression, and represents a
syntactically correct ExpressionStatement.

You are neglecting to take seriously the often observed fact that
whenever you think something is the case the odds are better than 50/50
that it is not the case. Try to understand; the stuff in your head has
very little relationship with reality. You should not trust it.
You may shot now if you want to :) - I just expressed my
worthless opinion :)

You certainly did. It may help you progress towards some sort of
understanding of javascript is you did something about learning the
syntax of the language instead of trying to make it up off the top of
your head.

Richard.
 
V

VK

Richard said:
Surrounding the FunctionExpression with parenthesise does exactly that,
as the only construct that may commence with an opening parenthesis
token is an ExpressionStatement, the only Expression that may commence
with an opening parenthesis is the "Grouping operator"
PrimaryExpression, and the "Grouping operator" PrimaryExpression is only
allowed to contain an Expression.

With such magic power of parenthesis I could claim then my $1,000,000
for positively solving Entscheidungsproblem. Because of
FunctionExpression in JavaScript being a derivative case of lambda
calculus, Entscheidungsproblem is solved as easy and elegant as:

<html>
<head>
<title>Test</title>
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1">
<script type="text/javascript">
window.alert(
(function a(){}) == (function b(){})
);
</script>
</head>
<body>
<h1>Demo</h1>
</body>
</html>

Take it as a New Year joke. Nappy New Year!
:)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top