Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling a function before it is declared, browser independent?

Tags:

javascript

If I do this in my <head> tag:

<script type="text/javascript" src="foo.js"></script>

And inside foo.js I do this:

var foo = new Foo();
function Foo()
{
   //code here
}

Would this code reliably instantiate the variable foo even though its included above the function definition, or should I move it instead to the bottom of the file, like this:

function Foo()
{
   //code here
}
var foo = new Foo();
like image 987
Ali Avatar asked May 29 '12 01:05

Ali


3 Answers

Your example will work in any browser that follow the ECMAScript standard (all do at least with regards to this question).

See sections 10.3-10.5 of the specification.

First the local scope is set up and just thereafter the function body is actually run.

Read 10.5 (the section is really not very long) to understand why @meder's answer is right.

If you don't want to read the specs yourself:

10.5 tells to declare variables in that order (overwriting if a some name occurs twice):

Inheriting from outer scope = setting will affect the outer scope:

  • Variables of the surrounding scope.
  • The own function name.

Local scope = setting won't affect the outer scope:

  • The parameters (left to right).
  • The arguments object.
  • Declare all the inner variables (not overwriting the current value if any, undefined if none, yet)

All in all:

Returns the function x itself:

function x() {
    return x;
}

Returns the parameter x:

function x(x) {
    return x;
}

Returns the inner function x:

function x(x) {
    return x; // the return does no harm, x is already set
    function x() {} // before the actual body is evaluated
}

Also returns the inner function x:

function x(x) {
    var x; // in this case a no-op 
    return x;
    function x() {}
}

Returns 42:

function x(x) {
    var x = 42; // overwrite x in local scope
    return x;
    function x() {}
}

Returns the second argument:

function x(x,x) { // assign left to right, last one "wins"
    return x; // arguments[0] would still name the first argument
}

Returns 2 when x is called the second time, as x is set to the inner function:

function x() {
    x = function() { return 2; } // set x in outer scope
    return 1;
}
like image 161
kay Avatar answered Oct 02 '22 01:10

kay


It's only necessary to move it above if you define it via var, such as:

var Foo = function(){};
var foo = new Foo;

Otherwise, to my knowledge the interpreter reads function definitions in advance.

like image 37
meder omuraliev Avatar answered Sep 29 '22 01:09

meder omuraliev


As far as i know, JS does this to your code due to hoisting:

var foo;          //var declarations hoisted up
function Foo(){   //function declarations hoisted up
   //code here
}
foo = new Foo();  //the operation

so it should be fine. However, I'd not rely solely on hoisting because, for me at least, it's hard to debug when declarations are all over the place. For readability, order the code this way:

  • variable declarations
  • functions
  • operations

code 1:

console.log(foo); //undefined
var foo = new Foo();
console.log(foo); //Foo
function Foo(){
   //code here
}
console.log(foo); //Foo

//acts like:
var foo;          //var declaration hoisted up
function Foo(){}  //function declaration hoisted up
console.log(foo); //undefined
foo = new Foo();
console.log(foo); //Foo
console.log(foo); //Foo

code 2:

console.log(foo); //undefined
function Foo(){
   //code here
}
console.log(foo); //undefined
var foo = new Foo();
console.log(foo); //Foo

//acts like:
var foo;          //var declaration hoisted up
function Foo(){}  //function declaration hoisted up
console.log(foo); //undefined
console.log(foo); //undefined
foo = new Foo();
console.log(foo); //Foo
like image 33
Joseph Avatar answered Sep 29 '22 01:09

Joseph