6

According to the Google JavaScript style guide, function declarations should not be declared within blocks since this is not a part of ECMAScript. However, I'm not entirely clear on what counts as a block.

Specifically, I have a constructor function and I want to define a function within the scope of that constructor. Would this count as a function within a block, since it is within a set of {}? If so, does that mean every function declaration must be global?

Some code for good measure:

WRONG (?)

function Constructor() {
    function Shout () { alert('THE BEST UX IS IN ALL CAPS.'); }
}

RIGHT (?)

function Constructor() {
    var Shout = function () { alert('THE BEST UX IS IN ALL CAPS.'); };
}
Matthew James Davis
  • 12,134
  • 7
  • 61
  • 90

1 Answers1

25

A function is not a block. A block is (for example) what follows a while, for, or if.

First, understand that function declarations (function foo() {}) are hoisted to the top of the scope of their containing function (i.e., you can access a declared functions by name anywhere in the same scope as the declaration).:

foo();
function foo() { }

This out-of-order code is 100% legal because the declaration of foo is hoisted to above the foo() invocation. However, now imagine you have a conditional declaration:

if(false) {
    function foo() { }
}

From a language-design perspective, should foo be hoisted? The program flow will never enter the block, but we customarily hoist all declarations. Due to this confusion, declarations inside blocks are not part of the grammar defined by the ECMAScript spec (though each implementation does support this grammar, but causes a different, nonstandard effect in each).

Having a function inside another function does not carry this confusion:

function bar() {
    function foo() { }
}

It's obvious that foo will be hoisted to the top of bar (whenever it runs).

Thus, your first example is perfectly fine.

apsillers
  • 112,806
  • 17
  • 235
  • 239
  • Thought so. So what defines a block? A Google search indicates {}'s are blocks. This implies the obvious blocks if, else, for, while, try, catch. But function is ambiguous. – Matthew James Davis Jul 01 '13 at 17:44
  • 2
    @MatthewJamesDavis Functions always have the `function` keyword, followed by a sometimes optional identifier, followed by parentheses with an optional parameter list inside, followed by the braces with the function body inside. So it's not ambiguous. An empty block is ambiguous with an empty object literal though. – bfavaretto Jul 01 '13 at 18:01
  • 2
    @MatthewJamesDavis bfavaretto said it pretty clearly, but I'll try to reiterate: curly braces indicate a block *except* when they are part of an object literal or a function definition/expression. I know that seems like a bit of a tautology, but it's what the spec says. I just did a search and I agree with you that's it's hard to find a clear reference on the subject; regardless, now you know the truth of the matter! – apsillers Jul 01 '13 at 18:08
  • @apsillers + 1 "A function is not a block" - applies to **any function**, for example, is a **function expression** also not a considered a block? –  Jan 28 '23 at 18:01
  • 1
    @Daniel nope, not a block! Largely, the differences between func expressions and declarations are limited to hoisting and variable names (i.e., a named function expression `bar` like `foo(function bar(){ ... })` doesn't declare a variable named `bar`). The scope behavior inside both types should be identical, and neither is a block. – apsillers Jan 28 '23 at 18:21
  • thanks, @apsillers +1, last question, a function expression if I can put it inside a block but a function declaration can't, right? thanks in advance –  Jan 28 '23 at 18:32
  • 1
    @Daniel Exactly right (or maybe "shouldn't" instead of "can't"). To change my example above, there's no problem with `if(false) { do_blah(function foo() { }); }` because you would never expect this expression to create a variable named `foo` in any case (unlike the declaration, which normally would). – apsillers Jan 28 '23 at 19:04
  • The named function expression in this example looks like a function declaration, I guess they differ in that a named function expression is passed as a callback or assigned to something and the function declaration is just at the top-level of a scope, thanks +1 –  Jan 28 '23 at 19:25
  • 1
    @Daniel Exactly right, a func expression can look exactly like a declaration but it's used within a larger statement, like an assignment. A function declaration is technically a special kind of function expression that (1) always has a name (expressions can have names or not) and (2) is its own complete statement (i.e., can be the entire content between two semicolons) – apsillers Jan 28 '23 at 19:37