JavaScript Hoisting Explained
Written by Mike James   
Wednesday, 23 January 2013
Article Index
JavaScript Hoisting Explained
Subtle Considerations

Hoisting, a JavaScript feature that allows you to make forward references to functions and variables, can seem extremely complicated and arbitrary. Once you know the principle that governs what is going on, however, it just seems simple and very logical.

 

JavaScript has some language features that confuse beginners and experts in other languages alike - but it is often the case that the simple principle that lies behind the behavior just isn't explained. When it is it not only seems logical but simple and the only way to do the job.

So it is with "hoisting" a seemingly elaborate and complex piece of behavior that just seems to complicated things without any benefits.

First let's take a quick look at what the problem is that hoisting is intended to solve.

Forward References

In most programming language you use functions or procedures to break the program down into small manageable chunks. One small problem that is often not mentioned is the forward reference.

Suppose you want to use a function:

myFunction();

but this isn't defined until later in the program's text. Should the program fail because myFunction isn't defined or should the language allow you to use functions that are defined later in the text?

Early programming languages insisted that you declare everything at the start of the program. This solved the forward reference problem because all functions and variables for that matter where defined before the main program started and hence there was no possibility of a forward reference. But it had the disadvantage of forcing the programmer to put all the functions first and the main program last. This bottom up approach doesn't fit naturally with the top down way we read a program i.e. main program first.

Later and more programmer friendly languages were less strict about where you should declare things. These allow you to put function definitions anywhere within the text of the program and use them anywhere including before they were actually defined in the text.

The way that this works is usually that the compiler or language runtime "reads" the entire program file once just to find out what functions and variables you have used. Only after this first pre-run scan does the actual program execution start safe in knowledge that all global variables and functions are defined. This is what JavaScript does and it is the origin of the idea we usually call "hoisting".

JavaScript Forward References

JavaScript doesn't insist that you declare variables and it allows you to define functions anywhere you like and it allows you to use a function before its definition.

It does this by implementing "hoisting - a picturesque term inspired by the image of the declarations being yanked up to the top of their scope.

The rule is quite simple and it makes sense to state what it is and then explore some of its consequences.

  • Hoisting moves all declarations to the start of the function that contains them.

or

  • Hoisting moves all declarations to the start of their enclosing scope.

As scope in JavaScript is defined by functions the two definitions are the same.

If the declarations are not within a function then they are moved to the start of the main program which is the scope in this case.

In other words, JavaScript could have insisted that you define everything you are going to use at the start of the function that you use them in. Instead it automatically gathers things up and moves them to the correct position.

Of course it doesn't actually modify your program - but your program is run as if the declarations were at the start of the function.

The only complication is what exactly is a declaration in JavaScript?

The answer is any statement that doesn't actually get executed when the program runs. A declaration simply tells the program "compiler" or runtime something useful.

There are two examples of this in JavaScript - the function declaration and the variable declaration. So lets take a look at each in turn.

Function Declarations

It may not have impressed itself upon you with enough force but when you write the code for a function - nothing happens.

A function definition or declaration doesn't involve actually carrying out any operations - you are simply defining the function so that it can be invoked later.

For example, if you write

function myFunction(){
  instructions;
}

this doesn't actually execute the function or do anything in your program. The text of the function is simple a definition or declaration of what the function myFunction is.

The function is executed when it is invoked using the usual parentheses notation e.g.

myFunction();

actually executes the function.

By the rule of hoisting then any function definition should be moved to the start of the function that contains it.

For example:

myFunction();

function myFunction(){
 alert("myfunction called");
}

works perfectly even though myFunction is defined later in the program than it is used.

Hoisting causes the program to be treated as if it had been written as:

function myFunction(){
 alert("myfunction called");
}

myFunction();

That is as if the function definition had been written at the start of the program.

Hoisting gathers all your function definitions and moves them to the top of their scope - the main program or the function that they are declared in.

If this seems obvious to you then you have grown accustomed, perhaps too accustomed, to the benefits of hoisting.

As will become apparent hoisting of functions doesn't work if the program if changed in away that seems insignificant - see later.

Variable Declarations

Function declarations and hoisting is a simple idea compared to the complications of variable declarations - mainly because JavaScript provides too many exceptions to make things easy to use.

The most obvious sort of declaration is a variable declaration. For example:

var a;

declares variable a. Notice that variable a is declared and this means it exists but it doesn't have a value assigned to it - it is undefined. 

In JavaScript a variable can be undeclared or undefined and these two states are treated differently.

For example the simple program

var a=myGlobal;
alert(a);

results in an runtime ReferenceError - myGlobal is not defined at the first line.

If you change the program to:

var a=myGlobal;
alert(a);
var myGlobal;

Then you don't get a runtime exception and alert(a) displays undefined.

That is declaring a program after it has been used still has the effect of allowing it to be used without a runtime exception.

Once again hoisting has been put into action and the declaration var myGlobal has been treated as if it was at the start of the program i.e. as if the program was:

var myGlobal;
var a=myGlobal;
alert(a); 

When a variable hasn't been declared it doesn't exist and so generates an exception.

When a variable has been declared it exists and is initialized to undefined.



Last Updated ( Wednesday, 23 January 2013 )