JSHint complains when my JavaScript calls a function that is defined further down the page than the call to it. However, my page is for a game, and no functions are called until the whole thing has downloaded. So why does the order functions appear in my code matter?
http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting
I am groaning inside. Looks like I need to spend ANOTHER day re-ordering six thousand lines of code. The learning curve with javascript is not steep at all, but it is very loooooong.
tl;dr If you're not calling anything until everything loads, you should be fine.
Edit: For an overview which also covers some ES6 declarations (let
, const
): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Scope_Cheatsheet
This weird behavior depends on
Here's some examples.
bar(); //This won't throw an error
function bar() {}
foo(); //This will throw an error
var foo = function() {}
bar();
function bar() {
foo(); //This will throw an error
}
var foo = function() {}
bar();
function bar() {
foo(); //This _won't_ throw an error
}
function foo() {}
function bar() {
foo(); //no error
}
var foo = function() {}
bar();
This is because of something called hoisting!
There are two ways to define functions: Function declaration and function expression. The difference is annoying and minute, so let's just say this slightly wrong thing: If you're writing it like function name() {}
, it's a declaration, and when you write it like var name = function() {}
(or an anonymous function assigned to a return, things like that), it's a function expression.
var foo = 42;
//the interpreter turns it into this:
var foo;
foo = 42;
var foo = 42;
function bar() {}
//turns into
var foo; //Insanity! It's now at the top
function bar() {}
foo = 42;
The var
statements "throws" the creation of foo
to the very top, but doesn't assign the value to it yet. The function declaration comes next in line, and finally a value is assigned to foo
.
bar();
var foo = 42;
function bar() {}
//=>
var foo;
function bar() {}
bar();
foo = 42;
Only the declaration of foo
is moved to the top. The assignment comes only after the call to bar
is made, where it was before all the hoisting occurred.
bar();
function bar() {}
//turns to
function bar() {}
bar();
var foo = function() {}
foo();
//=>
var foo;
foo = function() {}
foo();
Just like regular variables, first foo
is declared at the highest point of the scope, then it is assigned a value.
bar();
function bar() {
foo();
}
var foo = function() {}
//=>
var foo;
function bar() {
foo();
}
bar();
foo = function() {}
As we've seen before, only the creating of foo
is hoisted, the assignment comes where it appeared in the "original" (un-hoisted) code. When bar
is called, it is before foo
is assigned a value, so foo === undefined
. Now in the function-body of bar
, it's as if you're doing undefined()
, which throws an error.