From: Johannes Baagoe on 21 Apr 2010 09:35 Lasse Reichstein Nielsen : > Johannes Baagoe : >> MDC's bone of contention is this: >> >> if (0) { >> function zero() { >> document.writeln("This is zero."); >> } >> } > It's worth noticing that the above is not valid ECMAScript. > The content of the if match either FunctionDeclaration or > FunctionExpression, but neither is allowed at that point > (FunctionDeclaration because it is not a Statement, but only a > SourceElement, i.e., it can only occur directly inside a function body > or at top-level, and FunctionExpression because a StatementExpression > may not start with "function"). Aha. Now that, I understand. It did seem curious to define functions conditionally in this `#ifdef`-like way. > I.e., it's an ECMAScript extension that Mozilla allows it - as a > "FunctionStatement". > The other browsers that also allow it are also extending ECMAScript, but > probably interpret it slightly differently. I see that 5th ed. addresses the problem: (12) NOTE Several widely used implementations of ECMAScript are known to support the use of FunctionDeclaration as a Statement. However there are significant and irreconcilable variations among the implementations in the semantics applied to such FunctionDeclarations. Because of these irreconcilable difference, the use of a FunctionDeclaration as a Statement results in code that is not reliably portable among implementations. IOW, avoid, unless for personal use or strictly controled intranets. Even there, it is hard to see any real benefit. If different functions are needed according to flags (say, various versions of an `assert` function for debugging), assign them to the same variable in conditions at the start of the code. [Very clear explanation of when "function foo() {}" is a function declaration, and when it is a function expression - many thanks !] >> if the "Identifier opt" part in the definition of FunctionExpression >> were removed, there would be no ambiguity at all. > There would also be no easy way to make recursive function > expressions. Using arguments.callee sucks (both performance-wise > and readability-wise). One could assign the function to a variable in the enclosing scope, but I have to agree that it useful to be able simply to name the function for the benefit of its internal scope. -- Johannes
From: Johannes Baagoe on 21 Apr 2010 11:22 Scott Sauyet : > I'm not sure what we're left with now besides terrible hacks like > the one you presented and rejected. At this point, I would say: 1. Declare the functions when there is no good reason for using function expressions. (Mere pursuit of cuteness does not qualify as a good reason, except for recreational purposes.) Thus, Richard Cornford's (function(x) { function fact(n) { return n > 0 ? n * fact(n - 1) : 1; } return fact(x); }(21)); 2. If function declarations are undesirable (e.g., for didactic reasons), assign the inner function to a variable in the outer function's scope: (function(x) { var fact = function(n) { return n > 0 ? n * fact(n - 1) : 1; } return fact(x); }(21)); > [1] http://yura.thinkweb2.com/named-function-expressions/ Very interesting, thanks a lot. -- Johannes
From: Johannes Baagoe on 21 Apr 2010 11:58 Richard Cornford : >>> Johannes Baagoe : >>>> If I want to define 21! inline using neither named function >>>> expressions >>>> nor function declarations, the best I have come up with is >>>> >>>> ((function() { >>>> return fact = function(n) {return n > 0 ? n * fact(n - 1) : >>>> 1;}; > ^^^^ > As that - fact - is undeclared there Ooops! I wonder how long I shall continue to make that mistake again and again. Allowing undeclared variables is bad IMHO, but making them *global* by default is even worse. It is one of the things I still hate in javascript, with semicolon insertion and a few others. > But then, why not an inner function declaration, as in:- > > ((function() { > function fact(n){ > return n > 0 ? n * fact(n - 1) : 1; > } > return fact; > }())(21)); > > - or the simpler:- > > (function(x) { > function fact(n){ > return n > 0 ? n * fact(n - 1) : 1; > } > return fact(x); > }(21)); Why not, indeed. >> I try to figure out whether there are cases >> where function expressions need be named, > Which I think must require an example situation where a named function > expression couldn't be replaced with an inner function declaration (that > there be a good reason for not doing so), or a very good argument > against function declarations. I do have an argument against function declarations : use function expressions from the very beginning in order to expose students to the notion of functions as first-class objects, and don't confuse them with another, more traditional approach at the same time. Whether it qualifies as "good" is of course debatable, not to mention "very good". Outside of introductory courses in either javascript or general programming, it is a non-starter. -- Johannes
From: Garrett Smith on 21 Apr 2010 14:21 Richard Cornford wrote: > Johannes Baagoe wrote: >> Garrett Smith : >>> Johannes Baagoe : >> >>>> If I want to define 21! inline using neither named function >>>> expressions >>>> nor function declarations, the best I have come up with is >>>> >>>> ((function() { >>>> return fact = function(n) {return n > 0 ? n * fact(n - 1) : >>>> 1;}; > ^^^^ > As that - fact - is undeclared there is a side effect of creating a Mentioned yesterday. | Syntactially, it could do without the excess grouping operator and | certainly can do without creating a global identifier within a | function. -- Garrett comp.lang.javascript FAQ: http://jibbering.com/faq/
From: Johannes Baagoe on 21 Apr 2010 15:16
[supercede] Ry Nohryb : > (function (fact) { > return fact= function (n) { > return n > 0 ? n * fact(n - 1) : 1; > }; > })()(21) Sure, if you don't object to variables (`fact`, in this case) that are global in the inner function. Stefan Weiss did, so I tried something else. Personally, I find your proposal fine, except that I don't understand the `fact` in the first line. > Note how clearly and unequivocally "()()" reveals two consecutive > function calls, much more than a muddy "())())". I'm not sure, I find (function () { var fact = function(n) { return n > 0 ? n * fact(n - 1) : 1; } return fact; }()(21)) at least as clear. > And "fact" was a global in yours. Yes, that makes you the third contributor who (quite rightly) points that out, and I've just noticed that the first to point it out points out that he pointed it out. I think I have got it by now :) -- Johannes |