202

This code always works, even in different browsers:

function fooCheck() {
  alert(internalFoo()); // We are using internalFoo() here...

  return internalFoo(); // And here, even though it has not been defined...

  function internalFoo() { return true; } //...until here!
}

fooCheck();

I could not find a single reference to why it should work, though. I first saw this in John Resig's presentation note, but it was only mentioned. There's no explanation there or anywhere for that matter.

Could someone please enlighten me?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Edu Felipe
  • 10,197
  • 13
  • 44
  • 41
  • 3
    In newer versions of firefox, this doesn't work if the code is in a try/catch. See this fiddle: http://jsfiddle.net/qzzc1evt/ – Joshua Smith Jan 30 '15 at 22:11

7 Answers7

254

The function declaration is magic and causes its identifier to be bound before anything in its code-block* is executed.

This differs from an assignment with a function expression, which is evaluated in normal top-down order.

If you changed the example to say:

var internalFoo = function() { return true; };

it would stop working.

The function declaration is syntactically quite separate from the function expression, even though they look almost identical and can be ambiguous in some cases.

This is documented in the ECMAScript standard, section 10.1.3. Unfortunately ECMA-262 is not a very readable document even by standards-standards!

*: the containing function, block, module or script.

Oreo
  • 529
  • 3
  • 16
bobince
  • 528,062
  • 107
  • 651
  • 834
  • I guess it's really not readable. I just read the section you pointed 10.1.3 and didn't get why the provisions there would cause this behavior. Thank's for the information. – Edu Felipe Nov 04 '08 at 16:16
  • 4
    @bobince Okay, I started to doubt myself when I couldn’t find a single mention of the term “hoisting” on this page. Hopefully these comments have enough Google Juice™ to set things right :) – Mathias Bynens Dec 22 '11 at 12:43
  • 2
    This is a popular question/answer combo. Consider updating with a link/excerpt to the ES5 annotated specification. (Which is a bit more accessible.) –  Jul 16 '12 at 17:58
  • 1
    This article has some examples: [JavaScript-Scoping-and-Hoisting](http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html) – Lombas Nov 11 '15 at 12:26
  • I found quite a few library use the function before definition, even some language allow it officially, ex. Haskell. To be honest, this might not be a bad thing, since you can write a bit more expressive in some cases. – windmaomao May 09 '20 at 14:59
54

It is called HOISTING - Invoking (calling) a function before it has been defined.

Two different types of function that I want to write about are:

Expression Functions & Declaration Functions

  1. Expression Functions:

    Function expressions can be stored in a variable so they do not need function names. They will also be named as an anonymous function (a function without a name).

    To invoke (call) these functions they always need a variable name. This kind of function won't work if it is called before it has been defined which means Hoisting is not happening here. We must always define the expression function first and then invoke it.

    let lastName = function (family) {
     console.log("My last name is " + family);
    };
    let x = lastName("Lopez");
    

    This is how you can write it in ECMAScript 6:

    lastName = (family) => console.log("My last name is " + family);
    
    x = lastName("Lopez");
    
  2. Declaration Functions:

    Functions declared with the following syntax are not executed immediately. They are "saved for later use" and will be executed later, when they are invoked (called upon). This type of function works if you call it BEFORE or AFTER where is has been defined. If you call a declaration function before it has been defined Hoisting works properly.

    function Name(name) {
      console.log("My cat's name is " + name);
    }
    Name("Chloe");
    

    Hoisting example:

    Name("Chloe");
    function Name(name) {
       console.log("My cat's name is " + name);
    }
    
Philip Stratford
  • 4,513
  • 4
  • 45
  • 71
Negin
  • 2,332
  • 17
  • 22
  • 1
    `let fun = theFunction; fun(); function theFunction() {}` will also work (Node and browsers) – fider Mar 15 '19 at 09:54
  • 1
    Is hoisting actually "calling the function before it is defined"? Raising the scope of a declared name so that it will be defined for other code under that scope -- that's roughly what JavaScript does to allow you to call the function before it's declared, and that's hoisting. – Noah Dec 01 '20 at 18:01
  • @fider while your example with mixing function declaration and expression is working I do not see a practical use case. So maybe you can show it. – Timo Jun 04 '22 at 04:42
  • 1
    @Timo no practical example here, it's "just an example" (eg. you can define core of your business logic at the top of your file and helper functions later). – fider Jun 07 '22 at 11:36
15

The browser reads your HTML from beginning to end and can execute it as it is read and parsed into executable chunks (variable declarations, function definitions, etc.) But at any point can only use what's been defined in the script before that point.

This is different from other programming contexts that process (compile) all your source code, perhaps link it together with any libraries you need to resolve references, and construct an executable module, at which point execution begins.

Your code can refer to named objects (variables, other functions, etc.) that are defined further along, but you can't execute referring code until all the pieces are available.

As you become familiar with JavaScript, you will become intimately aware of your need to write things in the proper sequence.

Revision: To confirm the accepted answer (above), use Firebug to step though the script section of a web page. You'll see it skip from function to function, visiting only the first line, before it actually executes any code.

dkretz
  • 37,399
  • 13
  • 80
  • 138
  • So generally html - including javascript - has a top down method of parsing code. However, functions go out of this route as they are read first, but only the function head (= first line). That is why function calls are possible before declaration. – Timo Jun 04 '22 at 04:46
5

Some languages have the requirement that identifiers have to be defined before use. A reason for this is that the compiler uses a single pass on the sourcecode.

But if there are multiple passes (or some checks are postponed) you can perfectly live without that requirement. In this case, the code is probably first read (and interpreted) and then the links are set.

Toon Krijthe
  • 52,876
  • 38
  • 145
  • 202
2

I have only used JavaScript a little. I am not sure if this will help, but it looks very similar to what you are talking about and may give some insight:

http://www.dustindiaz.com/javascript-function-declaration-ambiguity/

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
RailsSon
  • 19,897
  • 31
  • 82
  • 105
  • The link is no longer dead. – mwclarke Apr 30 '16 at 21:28
  • 4
    The link is dead. – Jerome Indefenzo Dec 14 '17 at 09:38
  • Here's a [snapshot](https://web.archive.org/web/20120221051041/http://www.dustindiaz.com:80/javascript-function-declaration-ambiguity) from archive.org. Looks like the author [took down](https://twitter.com/ded/status/950584482418978816) their whole website for having outdated content, not that this blog post falls into that category. – jkmartindale Aug 07 '18 at 18:41
1

The body of the function "internalFoo" needs to go somewhere at parsing time, so when the code is read (a.k.a parsing) by the JS interpreter, the data structure for the function is created and the name is assigned.

Only later, then the code is run, JavaScript actually tries to find out if "internalFoo" exists and what it is and whether it can be called, etc.

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
-4

For the same reason the following will always put foo in the global namespace:

if (test condition) {
    var foo;
}
Andrew Hedges
  • 21,688
  • 16
  • 67
  • 79
  • 8
    Actually, it's for very different reasons. The `if` block does not create a scope, while a `function()` block always creates one. The real reason was that the definition of global javascript names happens at compile phase, so that even if the code does not run, the name is defined. (Sorry it took so long to comment) – Edu Felipe Jul 19 '09 at 21:27