Hoisting

In JavaScript all function statements defined in a scope are read and made available before the rest of the code in that scope is executed. Variables declarations are also read in before hand and made available, but assignments to those variables aren't done until execution reaches them.

This gives the appearance that function statements and variable declaration are 'hoisted' above everything else in that scope, hoisting above being a metaphor for happening beforehand. This is really handy for some things. The declaration hosting avoids a whole class of silly bugs that could happen if it wasn't done. And the function statement hoisting lets you organize the main flow of your code at the top of a scope, and all the utility code down below (even after the return).

However, the two hoisting effects don't play well together in some cases. Say you have a utility function that has an external variable it uses to keep track of some state?

// WARNING: Hoisting bug. increment() increment() increment() log() // NaN // UTILITY CODE BELOW var count = 0 function increment () { count += 1 } function log () { console.log(count) }

Our log is telling us that count is not a number, but no error occurs. Well, that is surprising. It seems like we are adding 1 to 0 three times. in reality, we add 1 to undefined, because the assignment to 0 doesn't happen until after the rest of our code executes!

// WARNING: Hoisting bug. increment() increment() increment() log() // NaN // UTILITY CODE BELOW var count = 0 log() // 0 function increment () { count += 1 } function log () { console.log(count) }

Pretty clear when you look at it that way, but damn can it be a subtle one to find sometimes. Especially when you're switching back and forth between asynchronous and synchronous calls of these functions.

setTimeout(function () { increment() increment() increment() log() // 3 }, 0) // UTILITY CODE BELOW var count = 0 function increment () { count += 1 } function log () { console.log(count) }

So, despite some negative points for code organization, declare and initialize variables at the top of your scope. It will save you some pain down the road in ways that you might not even notice.

// It may not be clear why this // variable is here, but it's // worth needing to look for it. var count = 0 increment() increment() increment() log() // 3 // UTILITY CODE BELOW function increment () { count += 1 } function log () { console.log(count) }