开发者

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

开发者 https://www.devze.com 2023-04-03 01:38 出处:网络
The code in question is simple: console.log(\"So it begins.\"); foo(); function foo() { console.log(\"In foo().\"); }

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?


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


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.


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).

0

精彩评论

暂无评论...
验证码 换一张
取 消