6

I just ran into a problem when defining a function in a block scope. Consider the following program:

try {
    greet();

    function greet() {
        alert("Merry Christmas!");
    }
} catch (error) {
    alert(error);
}

I expected this program to alert Merry Christmas!. However in Firefox is gives me the following ReferenceError:

ReferenceError: greet is not defined

On Opera and Chrome it alerts the greeting as I expected it to.

Evidently Firefox treats the function inside the block scope as a FunctionExpression while Opera and Chrome treat it as a FunctionDeclaration.

My question is why does Firefox behave differently? Which implementation is more logical? Which one is standards compliant?

I understand that declarations in JavaScript are hoisted and so if the same function is declared in two or more different blocks in the same scope then there'll be a name conflict.

However wouldn't it be more logical to redeclare the function every time it's declared so that you can do something like this:

greet(); // Merry Christmas!

function greet() {
    alert("Merry Christmas!");
}

greet(); // Happy New Year!

function greet() {
    alert("Happy New Year!");
}

I think this would be very useful, in addition to solving the block scoping problem I described above.

Aadit M Shah
  • 72,912
  • 30
  • 168
  • 299
  • "redeclare the function every time it's declared so that you can do something like this" – they *are* re-referenced, only the declaration occurs once and it's hoisted. Haven't you confirmed in the previous paragraph, that you understand the hoisting? – katspaugh Dec 25 '12 at 05:32
  • 2
    Yes I do understand hoisting in JavaScript. No, my sentence is perfectly clear. What I'm trying to say is that every time the interpreter encounters a `FunctionDeclaration` (_every time it's declared_) it should only hoist it upto the previous declaration of the function in the same scope (_redeclare the function_). Since this feature doesn't exist in JavaScript you can't invalidate it by citing current JavaScript standards. It's simply a suggestion. A suggestion to implement multiple declarations of the same function in JavaScript. Hope that brings you some clarity. Merry Christmas @katspaugh – Aadit M Shah Dec 25 '12 at 05:50
  • Oh, I see. Thanks Lord it didn't occur to anyone on the ES board. Merry Christmas, Aadit! :) – katspaugh Dec 25 '12 at 05:58

1 Answers1

5

Actually, function declarations inside block scopes is expressly not standardized and the behavior is implementation dependent. Different implementation respond differently. You'd get the same weirdness if you tried to declare a function inside an if statement.

The ES5 spec recommends that implementers make function declarations inside blocks be marked as a warning or error.

Chris Tavares
  • 29,165
  • 4
  • 46
  • 63
  • So you shouldn't declare functions inside block scopes. Perhaps that's a good programming practice. – Aadit M Shah Dec 25 '12 at 03:45
  • beside javascript is async lang. so you need to define your function before you can call it – Omiga Dec 25 '12 at 04:28
  • @Janim007, the whole point of this question is that in JavaScript you *can* call a function topologically before it's defined. – katspaugh Dec 25 '12 at 05:34
  • 1
    @Janim007 - JavaScript is not an asynchronous language. In fact there's no JavaScript construct which adds asynchronicity to the language. The event loop and `setTimeout` are not features of the language. They are features of the DOM, and are required for interactive programming in web pages: http://stackoverflow.com/q/8852198/783743 – Aadit M Shah Dec 25 '12 at 05:41
  • 1
    JavaScript is rather ... loosely ... designed, and the "hoisting" behavior isn't actually anywhere in the language spec as such. Functions defined in block scope are, quite simply, undefined behavior. They need to be at either global scope or in the top level of a function, or you're in undefined implementation-will-do-whatever-it-wants land. It could work. It could give a "undefined" exception. It could format your hard drive, subscribe your mother to the sweet potato of the month club, or tie-dye your cat. It's undefined. At least it's not C's level of undefined behavior. – Chris Tavares Dec 25 '12 at 06:53
  • I had a hard time believing that changing the syntax in which I defined my closure could cause Firefox to fail to load a source file dependency (!) and Require.js in dev mode not even checking that dependencies sent back are `undefined` (!) but that is exactly what happened. Now I know to always declare closures as variables... – Steven Lu Jul 10 '15 at 22:25