Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the explanation of this behavior? (When are functions created?)

The code in question is simple:

console.log("So it begins.");
foo();
function foo() { console.log("In foo()."); }
console.log("So it ends.");

Why does foo() execute, before it is defined (retrospective edit: in Chrome and Safari)?

I tinkered with this a bit, testing the following code in Chrome, Safari and Firefox:

javascript:foo();function foo() { alert("Oh."); }

An alert is displayed in Chrome and Safari, while Firefox remains silent.

Is there any explanation for this surprising, inconsistent behavior?

like image 499
maligree Avatar asked Sep 07 '11 15:09

maligree


People also ask

What is function declaration and function expression?

A function expression is very similar to and has almost the same syntax as a function declaration (see function statement for details). The main difference between a function expression and a function declaration is the function name, which can be omitted in function expressions to create anonymous functions.

What is function declaration in JavaScript?

The function declaration (function statement) defines a function with the specified parameters. You can also define functions using the Function constructor and a function expression.

Is a function a statement?

Statements are essentially always an “imperative” task that must be carried out. On the other hand, functions are a collection of multiple code lines which you are able to call all at once. Functions themselves are not statements, because they are not an imperative task that must be performed.

Can you call a function before it has been defined JavaScript?

Hoisting. With JavaScript functions, it is possible to call functions before actually writing the code for the function statement and they give a defined output. This property is called hoisting. Hoisting is the ability of a function to be invoked at the top of the script before it is declared.


3 Answers

Javascript delarations always will be moved to the top. It's called hoisting:

  • Twitter Engineer (Ben Cherry) on that topic: http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting
  • http://net.tutsplus.com/tutorials/javascript-ajax/quick-tip-javascript-hoisting-explained/
  • http://bonsaiden.github.com/JavaScript-Garden/#function.scopes

Example that should work in all browsers: http://jsbin.com/abelus/edit

like image 104
binarious Avatar answered Sep 28 '22 17:09

binarious


While others explained the "hoisting" behavior of functions (I personally find calling it context preparation or pre-processing more clear than hoisting) the reason of the different behavior of Firefox remains unanswered.

To start with, you should know the difference between a Function Declaration and a Function Statement.

A Function Declaration, as in your example can happen only in two places, in global code (outside of any function) and directly within the Function Body of another function, for example:

function foo () {}

function bar () {
  function baz() {}
}

All the above functions are valid Function Declarations.

The ECMAScript Specification doesn't allow to define Function Declarations in other places for example within Blocks:

if (true) {
  function foo () {}
}

The above function should give you a SyntaxError exception, but most implementations are benevolent, and they will still pre-process (hoist) the function, even if the actual function is not reachable (e.g. if (false) { function bar() {} }).

In Firefox, Function Statements are allowed, meaning that the function definition actually happens when the control reaches that specific statement, for example:

if (true) {
  function foo () { return true; }
} else {
  function foo () { return false; }
}

Executing foo(); after the above statements, in Firefox will produce true, because the first branch of the if statement is actually executed.

In other browsers, foo(); produces false because all the functions are pre-processed when entering the execution context, and the last one will take precedence, even if the false branch of the if statement is never reached.

The Firebug console, executes its code wrapping it inside a try-catch block, that's why the function is not available before its declaration.

If you try on the console:

console.log(typeof f); // "undefined"
function f () {}

You will see that f isn't prepared yet, but if you wrap your code inside a function, you will see the expected behavior:

(function () {
  console.log(typeof f); // "function"
  function f () {}
})();

Again, that's because now f is defined as a Function Declaration, since it exist in the body of the anonymous function, and is not part of an statement Block.

like image 21
Christian C. Salvadó Avatar answered Sep 28 '22 16:09

Christian C. Salvadó


The behavior you are noticing is called function hoisting.

In a nutshell, functions that are defined using the syntax function foo() { ... } are "hoisted" to the top of the scope in which they are defined, thus allowing them to be called before being defined.

With that being said, this is an obscure part of JavaScript. It would not surprise me if there are differences in how browsers implement it (particularly if you are using an older version of firefox).

like image 23
riwalk Avatar answered Sep 28 '22 17:09

riwalk