Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

function syntax question

59 views
Skip to first unread message

Csaba Gabor

unread,
Apr 10, 2006, 11:44:46 AM4/10/06
to
I feel like it's the twilight zone here as several seemingly trivial
questions are bugging me.

The first of the following three lines is a syntax error, while the
last one is the only one that shows the alert. What is the essential
reason?

function () { alert('hi mom'); }();
function () { alert('hi dad'); }(8);
var x=function () { alert('hi bro'); }();

Csaba Gabor from Vienna

Martin Honnen

unread,
Apr 10, 2006, 11:54:29 AM4/10/06
to

Csaba Gabor wrote:

> The first of the following three lines is a syntax error, while the
> last one is the only one that shows the alert. What is the essential
> reason?
>
> function () { alert('hi mom'); }();
> function () { alert('hi dad'); }(8);
> var x=function () { alert('hi bro'); }();

The grammar as defined in the ECMAScript edition 3 specification knows a
function declaration and a function expression

13 Function Definition
Syntax
FunctionDeclaration :
function Identifier ( FormalParameterListopt ) { FunctionBody }
FunctionExpression :
function Identifieropt ( FormalParameterListopt ) { FunctionBody }

where only in the function expression the function name (Identifier) is
optional.

On the right side of the assigment operator you always have an
expression so what you have there will be interpreted as a function
expression.

The other could be made into expressions if you use parentheses e.g.
(function () { alert('hi mom'); }())


--

Martin Honnen
http://JavaScript.FAQTs.com/

Csaba Gabor

unread,
Apr 10, 2006, 12:34:34 PM4/10/06
to
Martin Honnen wrote:
> Csaba Gabor wrote:
>
> > The first of the following three lines is a syntax error, while the
> > last one is the only one that shows the alert. What is the essential
> > reason?
> >
> > function () { alert('hi mom'); }();
> > function () { alert('hi dad'); }(8);
> > var x=function () { alert('hi bro'); }();

...

> The other could be made into expressions if you use parentheses e.g.
> (function () { alert('hi mom'); }())

Fabulous Martin. Thanks for a speedy and clear answer.

In IE 6, the following code shows me that baz is undefined, as I
expected. However, in FF I get a semi random positive integer (usually
in the 30s or 40s). If I were to call window.setTimeout with a third
argument, then that is what baz would be. In IE, however, it would
stay undefined.

Should I consider the numeric type and semi random value of baz odd, or
do I deserve what I get because I haven't supplied the extra agrument
to window.setTimeout?

window.setTimeout(
function () {
return function(baz) {
return function(baz) {
alert("baz: " + typeof(baz) + " " + baz);
}
} ("bar");
} ("foo"), 0);

Michael Winter

unread,
Apr 10, 2006, 12:42:38 PM4/10/06
to
On 10/04/2006 16:44, Csaba Gabor wrote:

> The first of the following three lines is a syntax error, while the
> last one is the only one that shows the alert. What is the essential
> reason?
>
> function () { alert('hi mom'); }();

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

You intend for this to be a function expression, which is fine. However,
the statement as a whole is an expression statement, and they must not
start with either 'function' or '{'.

To define and immediately call a function object created using a
function expression, wrap the latter in parentheses:

(function () {
alert('...');
})();

> function () { alert('hi dad'); }(8);

You are being mislead by either Firefox or MSIE (both exhibit the same
behaviour). This is still a syntax error for the same reasons as above.
If you have Opera, evaluate the above and then open the Javascript Console.

As for why this second statement fails to trouble either IE or Fx, they
clearly implement a syntax extension. However, I'm at a loss for what
exactly they consider this to be.

It's unlikely to be a function expression as the parentheses that follow
could be reasonably interpreted as Arguments (thereby inferring a call).
I find it hard to believe that it could be a function declaration, as
one without an identifier doesn't make much sense.

Nevertheless, the different in error behaviour is likely to arise from
the fact the trailing parentheses are considered separate. That is:

function() { ... } /* First statement */
(...); /* Second statement */

In the first case, you present empty parentheses, but that's illegal;
they must contain an expression. In the second, you include a number,
therefore the second statement will be evaluated to that number. In
other words, you might as well have just written the number by itself.

> var x=function () { alert('hi bro'); }();

Assignment expressions, including var statement initialisers, can be
function expressions, with or without enclosing parentheses, and can be
called on evaluation.

f = function() {
};

and

f = (function() {
});

are equivalent, as are:

f = function() {
}();

and

f = (function() {
})();

Hope that helps,
Mike

--
Michael Winter
Prefix subject with [News] before replying by e-mail.

Martin Honnen

unread,
Apr 10, 2006, 12:59:54 PM4/10/06
to

Csaba Gabor wrote:


> Should I consider the numeric type and semi random value of baz odd,

No, it is kind of odd when you do not expect it, but the reasons
(timeout lateness) are given here:
<https://bugzilla.mozilla.org/show_bug.cgi?id=10637>
I wonder whether the W3C groups currently defining window and
setTimeout/setInterval will consider that issue and either specify that
parameter or specify that it should not be there. So far,
<http://www.w3.org/TR/Window/#timers> does not talk about any parameters
besides the function to call and the delay in milliseconds.

Csaba Gabor

unread,
Apr 11, 2006, 5:30:17 PM4/11/06
to
Michael Winter wrote:
> To define and immediately call a function object created using a
> function expression, wrap the latter in parentheses:
>
> (function () {
> alert('...');
> })();

Thanks also for your nice reply, Michael, and for your followup to my
second question, Martin (I noticed you submitted that bug report nearly
7(!) years ago). The responses have been very informative. I have a
final question about closures. When I consider the example below, frob
shows a value ("input" as expected), then baz is undefined (as
expected) and then the final alert shows frob as undefined.

var foo = function (baz) {
var res = typeof(frob)=="undefined" ? "" : frob;
alert ("frob: " + typeof(frob) + " " + res); }

function bar() {
return function(baz,frob) {
return function(baz) {
alert("frob: " + frob);
alert("baz: " + baz);
foo(); }} (7, "input");
}

bar()();


However, if I now take 'foo' in function bar and replace it with foo's
definition surround by parens (see below), then the third alert will
show me that frob has value "input". My question is: why is there a
difference, and how is it possible to wrap a named function foo
(external to bar, without frob as a named parameter) so that it can be
called within bar and know about non global frob.


function bar() {
return function(baz,frob) {
return function(baz) {
alert("frob: " + frob);
alert("baz: " + baz);
(function (baz) {
var res = typeof(frob)=="undefined" ? "" : frob;
alert ("frob: " + typeof(frob) + " " + res); })();
}} (7, "input");
}

bar()();


Regards,
Csaba

Lasse Reichstein Nielsen

unread,
Apr 11, 2006, 7:52:22 PM4/11/06
to
"Csaba Gabor" <dan...@gmail.com> writes:

> var foo = function (baz) {
> var res = typeof(frob)=="undefined" ? "" : frob;
> alert ("frob: " + typeof(frob) + " " + res); }
>
> function bar() {
> return function(baz,frob) {
> return function(baz) {

...


> foo(); }} (7, "input");
> }
>
> bar()();
>
>
> However, if I now take 'foo' in function bar and replace it with foo's
> definition surround by parens (see below), then the third alert will
> show me that frob has value "input". My question is: why is there a
> difference,

That's what closures are all about. When a closure is contained, the
scope chain at that point is stored as part of it, and it is reinserted
when the function is called.


When replacing the "foo" identifier, bound to a closure created in the
global scope, with a function expression, then that function expression
creates a closure containing the scope at that point. That scope contains
the variables frob and baz, which the global scope didn't.

> and how is it possible to wrap a named function foo
> (external to bar, without frob as a named parameter) so that it can be
> called within bar and know about non global frob.

You can't. The scope chain used to resolve variables in the body
of a function is created when the function expression/declaration
is evaluated to a closure. If you want values to be available to
that function body, you must pass them as parameters or store them
in variables that are part of the scope captured in the closure.

> return function(baz,frob) {
> return function(baz) {
...


> (function (baz) {
> var res = typeof(frob)=="undefined" ? "" : frob;

(in scope of "frob" paremeter declared above).

> alert ("frob: " + typeof(frob) + " " + res); })();
> }} (7, "input");
> }

The word "closure" means more than just "first class function".

Lisp has first class functions but dynamic scope, so a function
declaration with a free variable (one not bound by the expression
itself) will use the scope available at the call point, not the
declaration point.

Example (from Emacs Lisp):
(defun foo (x) (lambda (y) (+ x y))) ;; x free var in (lambda (y) (+ x y))
(let ((foo2 (foo 2))
(x 37))
(funcall foo2 4)) ;; yields 41, value of x not kept

Compare that to Javascript:
function foo(x) { return function(y) { return x + y; }; }
var foo2 = foo(2);
var x = 37;
alert(foo2(4)); // alerts 6, value of x stored in closure

Ditto for Scheme, a dialect of Lisp with static scope:
(defun foo (x) (lambda (y) (+ x y)))
(let ((foo2 (foo 2))
(x 37))
(foo2 4)) ;; yields 6 too.


The closure contains not only the body of the function, but also the
the free variables. And it's not just their values, it's the actual
variables, as a common error shows:

for (var i = 0; i < 10; i++) {
elems[i].onclick = function() {
alert("You clicked element number " + i);
};
}

Many would expect the above to add ten onclick handlers which each
alert a different number between 0 and 9.
However, no matter which element is clicked, you are told that you
clicked element number 10. That's because all ten closures[1] will
have the same scope chain stored in them, and in that scope chain
is one variable called "i" with the value "10" (after the loop is
done).
The way to avoid this problem is to create ten functions with
either different bodies or different scope chains. Different bodies
would suggest the Function constructor, and managing source code
at runtime is rarely a good idea. The way to create different scope
chains is to make new function calls:

elems[i].onclick = (function (elemNr) {
return function() {
alert("You clicked element number " + elemNr);
};
})(i);

or using the "with" operator:

with ( {elemNr : i} ) {
elems[i].onclick = function() {
alert("You clicked element number " + elemNr);
};
}


/L
[1] Actually, implementations may choose to create only one closure
here, since it knows the ten closures will be indistinguishable (same
body, same scope chain).
--
Lasse Reichstein Nielsen - l...@hotpop.com
DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
'Faith without judgement merely degrades the spirit divine.'

Csaba Gabor

unread,
Apr 11, 2006, 10:26:50 PM4/11/06
to
Lasse Reichstein Nielsen wrote:
> "Csaba Gabor" <dan...@gmail.com> writes:
>
> > var foo = function (baz) {
> > var res = typeof(frob)=="undefined" ? "" : frob;
> > alert ("frob: " + typeof(frob) + " " + res); }
> >
> > function bar() {
> > return function(baz,frob) {
> > return function(baz) {
> ...
> > foo(); }} (7, "input");
> > }
> >
> > bar()();
> >
> >
> > However, if I now take 'foo' in function bar and replace it with foo's
> > definition surround by parens (see below), then the third alert will
> > show me that frob has value "input". My question is: why is there a
> > difference,
>
> That's what closures are all about. When a closure is contained, the
> scope chain at that point is stored as part of it, and it is reinserted
> when the function is called.

YoW! You know, I've been using closures left and right since I learned
about them in September, 2003 at
http://groups.google.com/group/comp.lang.javascript/browse_frm/thread/94165d8695faf91d/
but I never ran into this issue before because I've always either used
anonymous function or called named functions with all relevant
parameters passed in the function call. So this notion of named
functions being bound to the environment they were created in never
made it home with me.

> When replacing the "foo" identifier, bound to a closure created in the
> global scope, with a function expression, then that function expression
> creates a closure containing the scope at that point. That scope contains
> the variables frob and baz, which the global scope didn't.
>
> > and how is it possible to wrap a named function foo
> > (external to bar, without frob as a named parameter) so that it can be
> > called within bar and know about non global frob.
>
> You can't. The scope chain used to resolve variables in the body
> of a function is created when the function expression/declaration
> is evaluated to a closure. If you want values to be available to
> that function body, you must pass them as parameters or store them
> in variables that are part of the scope captured in the closure.

Yes, that was my conclusion, too, but I wanted to make sure that my
empirical observations were correct. To give some context to the
question...that is, to explain why I asked them...the first two were
offshoots in writing up this last one.

This closure issue came up because I am storing an array of functions
(e.g. an editor needs to respond differently to each command), and then
I want to call each function in context. All of the functions have
been taking a small (ie. 2) number of arguments, one being an optional
repeat count. And this was working fine. I found that I needed to add
a third argument to one of the functions, which is to say that I simply
wanted to have that variable available to the function without passing
it in since I didn't want to put it in the formal parameter list of all
the other functions.

However, I came to the conclusion, as you have confirmed, that this
will not fly, and I didn't like the idea of storing the value as a
property of the function itself, nor of making it global. So, I
decided to make an object onto which I put any variable of interest
(sort of an oApplication object) as a property, and then I always pass
in that object as the single argument to the function that corresponds
to the action that is to be taken.
...

> or using the "with" operator:
>
> with ( {elemNr : i} ) {
> elems[i].onclick = function() {
> alert("You clicked element number " + elemNr);
> };
> }

I never used with this way...interesting...

Thanks again, Lasse, and for everyone contributing to this awesome
thread.
Csaba

0 new messages