Could you tell me why ?

J

Jorge

<html><head></head><body><script>

(function () {
var watch = "Hola !";
(function f () { alert(watch) })();
alert(typeof f);
})();

</script></body></html>

This yields:

Safari : "Hola !", "undefined".
FireFox : "function () watch { [native code] }", "undefined"

Could you (kindly, please) tell me why :

1.- FF turns watch into a native function.
2.- f remains undefined.

TIA,
--Jorge.
 
H

Henry

<html><head></head><body><script>

(function () {
var watch = "Hola !";
(function f () { alert(watch) })();
alert(typeof f);

})();

</script></body></html>

This yields:

Safari : "Hola !", "undefined".
FireFox : "function () watch { [native code] }", "undefined"

Could you (kindly, please) tell me why :

1.- FF turns watch into a native function.
2.- f remains undefined.

JavaScript(tm) objects have - watch - and - unwatch - methods (as an
aid to debugging). When a Function Expression is provided with the
optional Identifier (your 'f' in this case) the specified behaviour is
to create the corresponding function object with an additional object
at the top of the scope chain that is referred to by the function's
internal [[Scope]] property and give that object a name which
corresponds with the Identifier and a value that refers to the
function object. A side effect of this is that when the function is
executed it has an ordinary javascript object on its scope chain and
so all Identifiers used within the function that correspond with the
named properties of ordinary javascript objects will resolve as
properties of that particular object if not masked by formal
parameter, local variable or inner function declarations. And where
the ordinary javascript object have a - watch - property (such as in
JavaScript(tm)) then the Identifier - watch - will resolve as a
reference to the -watch - method of that object.

f "remains undefined" because the FunctionExpression with optional
Identifier does not result in the creation of a named property of the
Activation/Variable object for the execution context in which it is
evaluated (it is not a FunctionDeclaration, which would). That is
until you try this in IE and see the bug that makes using the optional
Identifiers with FunctionExpressions such a bad idea that you would be
best off never attempting it.
 
J

Jorge

JavaScript(tm) objects have - watch - and - unwatch - methods (as an
aid to debugging). When a Function Expression is provided with the
optional Identifier (your 'f' in this case) the specified behaviour is
to create the corresponding function object with an additional object
at the top of the scope chain that is referred to by the function's
internal [[Scope]] property and give that object a name which
corresponds with the Identifier and a value that refers to the
function object. A side effect of this is that when the function is
executed it has an ordinary javascript object on its scope chain and
so all Identifiers used within the function that correspond with the
named properties of ordinary javascript objects will resolve as
properties of that particular object if not masked by formal
parameter, local variable or inner function declarations. And where
the ordinary javascript object have a - watch - property (such as in
JavaScript(tm)) then the Identifier - watch - will resolve as a
reference to the -watch - method of that object.

Ahh.., so there was beforehand a .watch() method... !
But not in Safari... etc right ?
Only in FireFox ?
And, is that method a part of the standard ?
Why do you write ***JavaScript(tm)*** ?
f "remains undefined" because the FunctionExpression with optional
Identifier does not result in the creation of a named property of the
Activation/Variable object for the execution context in which it is
evaluated (it is not a FunctionDeclaration, which would). That is
until you try this in IE and see the bug that makes using the optional
Identifiers with FunctionExpressions such a bad idea that you would be
best off never attempting it.

Hmm, I was expecting (function funcName () {})(); to yield a defined
funcName in that context.
Why is that a bad idea ?
You could always have used an unnamed function instead, I mean, if you
didn't intend to get funcName defined... ?

(function () {
var watch = aVar = "Hola !";
(function f () {
alert(aVar);
alert(watch);
alert(typeof f);
})();
alert(typeof f);
})();

IE8b : "Hola !", "Hola !", "function", "function" <- You're right,
IE did it !
Safari : "Hola !", "Hola !", "function", "undefined"
FireFox : "Hola !", "native function ()", "function", "undefined"

Thanks for sharing,
--Jorge.
 
H

Henry

Ahh.., so there was beforehand a .watch() method... !
Yes.

But not in Safari... etc right ?

Not yet, but Safari could add one at any moment. Opera's ECMAScript
implementation has - watch - and unwatch - methods on its object for
compatibility with JavaScript(tm), and Safari does do some things for
similar compatibility.
Only in FireFox ?

Not only (and that is assuming that "FireFox" is taken to mean all
Mozilla/Gecko based web browsers (and there are 20 odd of them by
now).
And, is that method a part of the standard ?

No. But the standard allows implementations to provide extensions and
those methods are an extension.
Why do you write ***JavaScript(tm)*** ?

JavaScript, with an uppercase J and an upper case S, is the trademark
name of what is now a single ECMAScript implementation (the one that
originated at Netscape, is now the responsibility of the Mozilla
foundation and appears in Firefox/Mozilla/Gecko browsers). There are
numerous other ECMAScript implementations, such as JScript(tm) in IE
browsers. I tend to use 'javascript' or 'Javascript' (with the non-
trademark capitalisation) to refer to geniality of ECMAScript
implementations (as do many others) and the trademark names to refer
to the specific implementations unambiguously (especially with the
"(tm)" extension) (were they have such names (and I know what those
names are)).
Hmm, I was expecting (function funcName () {})(); to yield a defined
funcName in that context.

But the specification says that should not happen. FunctionExpressions
and FunctionDeclarations are not handled the same way regardless of
how similar they may appear in some cases.
Why is that a bad idea ?

Which? Thinking it should create a named property of the variable
object or using the optional Identifiers with FunctionExpressions? The
former is a bad idea because it is at odds with the specification and
the reality of most implementations of that specification. The latter
is a bad idea because IE does not conform to the specification in this
area and what it does do is sufficiently strange as to be
problematic.
You could always have used an unnamed function instead,
I mean, if you didn't intend to get funcName defined... ?

The use of the optional Identifier with FunctionExpressions is to
allow code inside the function body to refer to the function object by
name (rather than using - arguments.callee -).
(function () {
var watch = aVar = "Hola !";
(function f () {
alert(aVar);
alert(watch);
alert(typeof f);
})();
alert(typeof f);
^^^^^^^^^^^^^^
Try moving this line to above the evaluation of the function
expression to see how badly IE is behaving here.
})();

IE8b : "Hola !", "Hola !", "function", "function" <- You're right,
IE did it !
<snip>
Yes, and if you it you would discover that the function object that
results form the evaluation of the function expression is not the same
function object as can be referred to using the Identifier in the
containing context.
 
J

Jorge

Not yet, but Safari could add one at any moment. Opera's ECMAScript
implementation has - watch - and unwatch - methods on its object for
compatibility with JavaScript(tm), and Safari does do some things for
similar compatibility.


Not only (and that is assuming that "FireFox" is taken to mean all
Mozilla/Gecko based web browsers (and there are 20 odd of them by
now).

I see. But Opera behaves the same as Safari.
FF3 behaves as FF2, but it's JS is not spiderMonkey, isn't it ?
The other spiderMonkeys I've tested all behave as FF2.

--Jorge.
 
J

Jorge

But the specification says that should not happen. FunctionExpressions
and FunctionDeclarations are not handled the same way regardless of
how similar they may appear in some cases.


Which? Thinking it should create a named property of the variable
object or using the optional Identifiers with FunctionExpressions? The
former is a bad idea because it is at odds with the specification and
the reality of most implementations of that specification. The latter
is a bad idea because IE does not conform to the specification in this
area and what it does do is sufficiently strange as to be
problematic.


The use of the optional Identifier with FunctionExpressions is to
allow code inside the function body to refer to the function object by
name (rather than using - arguments.callee -).


   ^^^^^^^^^^^^^^
Try moving this line to above the evaluation of the function
expression to see how badly IE is behaving here.





<snip>
Yes, and if you it you would discover that the function object that
results form the evaluation of the function expression is not the same
function object as can be referred to using the Identifier in the
containing context.

Ok :

<html><head></head><body><script>

(function () {
var f2, watch = aVar = "Hola !",
d = function (p) { document.write(p) },
n = "<br>";

d("typeof f: "+(typeof f)+n);
d(n+"Entering f..."+n+n);
f2 = (function f () {
d("aVar: "+aVar+n);
d("watch: "+watch+n);
d("typeof f: "+(typeof f)+n);
d("(f === arguments.callee): "+(f === arguments.callee)+n);
return arguments.callee;
})();
d(n+"Leaving f..."+n+n);
d("typeof f: "+(typeof f)+n);
d("typeof f2: "+(typeof f2)+n+"f2 === f: ");
try { d((f2 === f)+n) } catch (e) {
d("throws an exception"+n); }
})();

</script></body></html>

*************** IE5 Mac :
typeof f: function
Entering f...
aVar: Hola !
watch: Hola !
typeof f: function
(f === arguments.callee): true
Leaving f...
typeof f: function
typeof f2: function
f2 === f: true <-- Yeah !

*************** IE8b Win :
typeof f: function

Entering f...

aVar: Hola !
watch: Hola !
typeof f: function
(f === arguments.callee): false <-- What ?

Leaving f...

typeof f: function
typeof f2: function
f2 === f: false <-- What you said (weird !)

*************** Safari, Opera : Win & Mac :
typeof f: undefined

Entering f...

aVar: Hola !
watch: Hola !
typeof f: function
(f === arguments.callee): true

Leaving f...

typeof f: undefined
typeof f2: function
(f2 === f) throws an exception

*************** SpiderMonkeys : FF2, Camino, SeaMonkey, NS9...
typeof f: undefined

Entering f...

aVar: Hola !
watch: function watch() { [native code] }
typeof f: function
(f === arguments.callee): true

Leaving f...

typeof f: undefined
typeof f2: function
(f2 === f) throws an exception

*************** FF3.0pre : "MineField" :
typeof f: undefined

Entering f...

aVar: Hola !
watch: function watch() { [native code] }
typeof f: function
(f === arguments.callee): true

Leaving f...

typeof f: undefined
typeof f2: function
(f2 === f) throws an exception

*************** ***************

-IE5Mac did what I was expecting... (!)
-IE8b does weird things : f !== arguments.callee, f2 !== f... !
-Safari as Opera.
-Mozillas : all equal.

--Jorge.
 
H

Henry

On May 7, 2:27 pm, Henry wrote:
-IE5Mac did what I was expecting... (!)

Expect it as you may, it is still objectively incorrect behaviour for
an ECMAScript implementation (a bug).
-IE8b does weird things : f !== arguments.callee, f2 !== f... !

Yes, two function objects and if the one that results form the
function expression attempts to call itself using its name it will
actually call the other function object.
-Safari as Opera.

There remain two possible explanations of not resolving the - watch -
identifier on the object added to the innermost function's scope
chain. One is that the native objects don't have - watch - method
(which is allowed/normal) and the other is that the object added to
the scope chain was not a (normal) native object (which is incorrect
and so would be an implementation bug). Testing the latter might
involve declaring something like a - toString - variable in the
containing function and seeing how a - toString - identifier is
resolved from the inner function (as all native objects have toString
methods).
-Mozillas : all equal.

Hence the general advice not to use the optional Identifiers with
FunctionExpressions. There are so many (different) implementation bugs
that expecting any particular behaviour when using them is not
practical.
 
J

Jorge

Expect it as you may, it is still objectively incorrect behaviour for
an ECMAScript implementation (a bug).


Yes, two function objects and if the one that results form the
function expression attempts to call itself using its name it will
actually call the other function object.

Not sure exactly what do you mean ?
Yet another one more IE bug ?
Because I see no more weird things here :

*********** IE5 Mac
.typeof f: function
.(f === arguments.callee.1): true

..(f === arguments.callee): true
..(arguments.callee.1 === arguments.callee.2): true

*********** IE8b Win
.typeof f: function
.(f === arguments.callee.1): false

..(f === arguments.callee): true
..(arguments.callee.1 === arguments.callee.2): false

*****

<html><head></head><body><script>

(function () {
var n = "<br>", d = function (p){ document.write(p+n) };

(function f () {
var a = arguments;
if (a.length) {
d(n+"..(f === arguments.callee): "+(a[0] === a.callee));
d("..(arguments.callee.1 === arguments.callee.2): "+(a[1] ===
a.callee));
} else {
d(".typeof f: "+(typeof f));
d(".(f === arguments.callee.1): "+(f === a.callee));
f(f, a.callee);
}
})();
})();

</script></body></html>

Thanks,
--Jorge.
 
H

Henry

Not sure exactly what do you mean ?

I mean precisely what I wrote.
Yet another one more IE bug ?
Because I see no more weird things here :

*********** IE5 Mac
.typeof f: function
.(f === arguments.callee.1): true

..(f === arguments.callee): true
..(arguments.callee.1 === arguments.callee.2): true

*********** IE8b Win
.typeof f: function
.(f === arguments.callee.1): false

..(f === arguments.callee): true
..(arguments.callee.1 === arguments.callee.2): false

*****
<snip>
I see that when the function object that resulted from the
FunctionExpression attempted to call itself by name in Windows IE it
actually ended up calling a different function, which is precisely
what I described.
 
J

Jorge

There remain two possible explanations of not resolving the - watch -
identifier on the object added to the innermost function's scope
chain. One is that the native objects don't have - watch - method
(which is allowed/normal) and the other is that the object added to
the scope chain was not a (normal) native object (which is incorrect
and so would be an implementation bug). Testing the latter might
involve declaring something like a - toString - variable in the
containing function and seeing how a - toString - identifier is
resolved from the inner function (as all native objects have toString
methods).

See, I found no watches in the Opera... :)

DOM object : window.watch :
javascript:alert(typeof window.watch)
Safari, Opera : undefined, FF : function

DOM.method.watch :
javascript:alert(typeof alert.watch)
Safari, Opera : undefined, FF : function

regular function.watch :
javascript:(function(){alert(typeof arguments.callee.watch)})()
javascript:alert(typeof (new Function().watch))
javascript:alert(typeof (function(){}).watch)
Safari, Opera : undefined, FF : function

regular object.watch :
javascript:alert(typeof (new Object()).watch)
javascript:alert(typeof {}.watch)
Safari, Opera : undefined, FF : function

JCore native Function constructor watch :
javascript:alert(typeof Function.watch)
Safari, Opera : undefined, FF : function

Thanks,
--Jorge.
 
J

Jorge

On May 8, 4:02 pm, Jorge wrote:
<snip>
I see that when the function object that resulted from the
FunctionExpression attempted to call itself by name in Windows IE it
actually ended up calling a different function, which is precisely
what I described.

I couldn't find weird that a call to f() !== a call to
arguments.callee(),
because we already knew that f !== arguments.callee on the first
entry... ?

But I get what you mean.

Thanks,
--Jorge.
 
T

Thomas 'PointedEars' Lahn

Considering Section 2, on what part of the Specification do you base your
assessment?
See, I found no watches in the Opera... :)
*g*

DOM object : window.watch : javascript:alert(typeof window.watch) Safari,
Opera : undefined, FF : function

DOM.method.watch : javascript:alert(typeof alert.watch) Safari, Opera :
undefined, FF : function

regular function.watch : javascript:(function(){alert(typeof
arguments.callee.watch)})() javascript:alert(typeof (new
Function().watch)) javascript:alert(typeof (function(){}).watch) Safari,
Opera : undefined, FF : function

regular object.watch : javascript:alert(typeof (new Object()).watch)
javascript:alert(typeof {}.watch) Safari, Opera : undefined, FF :
function

JCore native Function constructor watch :

What is JCore?
javascript:alert(typeof Function.watch) Safari, Opera : undefined, FF :
function

In the Gecko AOM/DOM, some host objects inherit from the object referred to
by JavaScript's Object.prototype, which provides the watch() method there.

// true
window.__proto__.__proto__.__proto__ === Object.prototype

http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Object:watch


PointedEars
 
H

Henry

Considering Section 2, on what part of the Specification do you
base your assessment?
<snip>

Section 13; the first step in the algorithm for "FunctionExpression :
function Identifier ( FormalParameterList<opt> ) { FunctionBody}". The
object added to the scope chain should be an object created "as if by
the expression new Object()"; a (normal) native object, including any
extension method that would appear on any other object created with
new Object().
 

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

No members online now.

Forum statistics

Threads
473,997
Messages
2,570,239
Members
46,827
Latest member
DMUK_Beginner

Latest Threads

Top