I'm really skeptical about this. Using function expressions has some quite subtle consequences (hoisting, accidental/unintended closures) which you automatically avoid when using function declarations. Function declarations are also very useful since they allow you to use the function before it is defined (in the code), which mean you can read the code (and use the function name as an abstraction) without having to scroll past all function implementations.
To expand a bit on the accidental closures part, a variable bound by a closure is an implicit dependency of that function. By breaking function expressions out as function declarations you can be more explicit about what kind of input that piece of code needs from the outside. I just think overuse (nesting etc.) of closures can lead to some quite messy code, it gets harder to reason about when a variable was actually bound and to what.
Using function expressions has some quite subtle consequences (hoisting, accidental/unintended closures) which you automatically avoid when using function declarations.
Obviously, there is the issue of hoisting the function's expression as well as its name when you use a declaration, versus only hoisting the variable when you use an expression.
Are there any other subtle hoisting consequences to consider?
With respect to accidental/unintended closures, can you elaborate on this? Perhaps provide an example showing why a function assigned as an expression creates an accidental closure but a function that is declared does not?
You say: A variable bound by a closure is an implicit dependency of that function. By breaking function expressions out as function declarations you can be more explicit about what kind of input that piece of code needs from the outside.
I admit I don't understand at all how a function declaration changes the behaviour of its free variables. What is there about a function declaration that provides more control over its dependencies on its enclosing environment?
> Are there any other subtle hoisting consequences to consider?
I can't think of any, other than consequences from the hoisting such as making the order of the variable declarations important (whereas it's not important if they were function declarations).
> I admit I don't understand at all how a function declaration changes the behaviour of its free variables. What is there about a function declaration that provides more control over its dependencies on its enclosing environment?
You are correct, it doesn't. I realise now that in my head I was not strictly comparing function declarations to function expressions, but rather top-level function declarations (like in C) versus function expressions defined at some inner scope.
Using function declarations at any other scope than the top-level is something I would consider an anti-pattern (if I had to use that word), since it's very confusing to programmers from other C-like languages.
> With respect to accidental/unintended closures, can you elaborate on this? Perhaps provide an example showing why a function assigned as an expression creates an accidental closure but a function that is declared does not?
So, as I said above I was referring to function expressions versus top-level function declarations, which probably makes this question obsolete. I should perhaps have said unnecessary closures, since if you capture 10 variables but only use one then perhaps you should rethink your design. Closures are super useful but they tend be abused (yay access to everything!) which leads to bad design (low separation of concerns and overall spaghetti code).
I suspect from your questions you already know all of this. I should have been more clear that I was not talking about any semantic differences between function declarations and function expresses, since you are correct in that there are none, but rather the design choice of using a function expression (and thereby capturing the variables in scope) versus breaking it out as a top-level function declaration thus making it necessary to explicitly state all input as arguments.
Personally whenever I see a javascript programmer doing this with simple functions, I think it shows a pretty fundamental misunderstanding of programming to me.
The guy even hints at the misunderstanding in his code with the comment 'Makes it easier to understand "functions as an object"'. So what, most other languages have this now, but you don't see them taking one of the fundamental building blocking of programs and code encapsulation, simple function declaration, and bunging it in the middle of another method.
It's much clearer using the style for closures only so you're explicitly making it clear 'hey look, I'm making a closure people!!'.
It's a style that's practically begging for you to write heavily coupled code and is anti-code reuse. It's a terrible habit, it was all started by Crockford's the good parts, a style he just happened to be using at the time as far as I can tell, and even he doesn't even do it any more.
It also makes your code harder to read as you can't just move the function declarations wherever you want, just in case.
IMO you should never assign a function to a variable unless you are going to use it as a closure or actually use it like a variable and potentially over-ride it later in your code.
To me it's a massive code smell when I see simple functions assigned to variables.
Sorry - accidentally downvoted (this is what happens when I HN on an iPad). But thank you - agreed. I couldn't figure out what the parent comment was actually referring to either!
with p being an alias to Array.prototype.shift.apply, put the second arg to the top of the former as an array... it's generally wrapped in a utility function... With that in place my entire prototype's functions are just pass through to static Foo.fn .. in general this makes it easier to test modules that are instance objects.
Though prefer to have utility modules over modules that expose an object constructor... Exception being Models, which inherit from EventEmitter2
that's pretty much what I meant by wrapped in a utility function... generally... something akin to explitize(ConstructorName, 'methodname') .. so that the passthrough call(s) can be shimmed/mocked for testing...
Actually, the reason you can use the function at a place in code before it's defined is actually because of variable hoisting. The name of the function is hoisted to the beginning of the scope in which it's defined. (this may be what you mean, but it was unclear from the comment)
But I agree that I don't think doing var func = function(){}; is in any way better than a normal function declaration. Actually, I think it's a bit ridiculous to even have one recommended over the other.
Yes, a function definition is hoisted too but its implementation is always hoisted together with its declaration, preventing some bugs caused by variable hoisting.
The main argument for a function expression assignment is that it behaves like everything else where as the function declaration does some magic. As long as you and all your team members are aware of said magic it's probably fine but personally I would side on consistency.
I also doubt its enforcing of good semicolon habits, considering that semicolons are not needed after many a statement in C-like languages, including Javascript.
This seems more of enforcing one's personal opinion than anything else, to me.
It does bite you if you are not careful, for example:
(function(){
var foo = 1;
console.log(foo);
})() // Semicolon missing!
(function(){
var bar = 1;
console.log(bar);
})()
It's ambigous for the parser so this will throw a TypeError: "undefined is not a function". So overall I don't think is a stylistic choose but a safety one.
Sure, but the solution should not be "semicolon everywhere" but rather "semicolon where necessary", where necessary also includes places that can produce ambiguities depending on the code directly following (or after minification). Omitting a semicolon after a function declaration will never produce ambiguous code.
What I'm still arguing for is that "enforcing semicolon habits" is not a compelling argument for using function expressions over function declarations. (Perhaps you're talking about semicolons in general, which is something I would rather not get into :)
Everywhere where it _can_ create an ambiguity (regardless if it does or not); having to look at previous unrelated code to see if you need or not a semicolon is inefficient; better put it everywhere where any adjacent code can create ambiguity.
And function declarations can create ambiguous code, because functions are first class citizens on JavaScript it means code like this is valid:
var foo = function (bar){
console.log(bar);
}
but for the lacking semicolon it throws an error if it is followed by:
Rather than putting a semi-colon after every function declaration, I would suggest the Lua convention -- put the semi-colon at the beginning of the line that could cause issues. An empty statement is valid is JavaScript, so this should work in all cases I can think of:
;(function(){
var foo = 1;
console.log(foo);
})()
In Lua, whitespace is very nearly all the same. For example:
a = 1 b = 2
c
=
3
is valid Lua code. However, lines that start with parens have the same ambiguity:
a = something
(expression)(arguments)
--Could be:
a = something(expression)(arguments);
--Also could be:
a = something;
(expression)(arguments);
The parser will complain about the ambiguity. If the intention is to have 1 statement, they should probably be on the same line, otherwise the convention is to put the semi-colon at the beginning of the second line:
That would be a change of paradigm because no JavaScript standard -or library- does that. Plus it feels wrong because the spoken language equivalent would be something like:
The quick brown fox jumps over the lazy dog
. The fox didn't say anything that day
, because in all honesty what does the fox say
?
I think I've been unclear. When I say function definition I'm referring to this:
function foo() {
console.log('bar');
}
And when referring to a function expression I'm talking about this:
var foo = function () {
console.log('bar');
};
The latter needs to be terminated with a semicolon to prevent ambiguity (in some situations), while the former does not. This for example is valid JavaScript:
I don't know about others, but there's really no chance I'd be physically able to read those words without things like this. My eyes blur and I feel a physical strain on them - like I'm trying to do some type of eyeball aerobics.
I literally can't read more than about a sentence without having to look away a few moments and then return.
I can read grey on grey just fine, even on my old laptop with its terrible color and worse grey resolution. Moreover, that site isn't grey on grey, it's grey on light cream ( https://en.wikipedia.org/wiki/Cream_(colour) ).
If you haven't already, go to a doctor and get your eyes checked out. What you're describing is not typical.
Are you really going to write
"var getData = function getDataF () {
};"
instead of
"function getData() {}"
for pseudo benefits like
* 1. Makes it easier to understand "functions as an object".
* 2. It enforces good semicolon habits.
* 3. Doesn't have much of the baggage traditionally associated with functions and scope.
And the recommendation to avoid i++ due to "excessive trickiness?" followed by a recommendation to use while(i--) with i initialized somewhere else as a for loop substitute? What the heck? That sounds terrible.
I'm really skeptical about this. Using function expressions has some quite subtle consequences (hoisting, accidental/unintended closures) which you automatically avoid when using function declarations. Function declarations are also very useful since they allow you to use the function before it is defined (in the code), which mean you can read the code (and use the function name as an abstraction) without having to scroll past all function implementations.
To expand a bit on the accidental closures part, a variable bound by a closure is an implicit dependency of that function. By breaking function expressions out as function declarations you can be more explicit about what kind of input that piece of code needs from the outside. I just think overuse (nesting etc.) of closures can lead to some quite messy code, it gets harder to reason about when a variable was actually bound and to what.