Javascript hoisting explained

Often I see problems arise when people try to tackle Javascript. Taking a certain behavior for granted can get them frustrated. Javascript has little differences but they can cause unexpected results if not taken into account. One of those differences is the way it handles scope.

What is hoisting?

In Javascript, you can have multiple var-statements in a function. All of these statements act as if they were declared at the top of the function. Hoisting is the act of moving the declarations to the top of the function.

Hoisting versus block-scope

In most programming languages there’s something called block-scope. Basically what it means is that every variable declared within a block is only visible within that block. The following code snippet in c# shows this behavior:

Normally you would expect the first alert to display the value of the global variable since you haven’t overwritten it yet. However, since the declaration is actually hoisted to the top it overwrites it at the start of the function.The following code is functionally equivalent:

As you can see, both implementations are valid and you can call them using the same syntax. This might lead you to believe that they are in fact equivalent. However, there is a small difference when it comes to hoisting: function declarations get hoisted completely (name AND implementation) whereas function expressions get only the variable declaration hoisted and not the implementation. Let’s look at an example:

In this example you can see that, as with normal variables, just the presence of mymethod and mysecondmethod inside the function moves them to the top. However, mymethod (a function declaration) gets hoisted completely and therefore is available everywhere inside the function. On the other hand, mysecondmethod (a function expression) has only the var declaration hoisted, which prevents the global method from being seen but is not usable as a function until it’s assigned.

Best practices

From the examples, it’s obvious that the hoisting behavior Javascript exhibits can lead to confusing results and make it difficult to read code. Therefore you should follow some best practices.What you really want when you read code, is that it clearly states what it does. Since you know it’s moving the variable declarations to the top, you should do this explicitly, so it’s obvious that they’re there. Consider the following examples (the first one is the “wrong” one, the second example show a better version):

Sidenote

For completeness sake, I need to mention that behind the scenes things are actually implemented a little bit different. The ECMAScript standard does not define hoisting as “the declaration gets moved to the top of the function”. Handling code happens in two steps: the first one is parsing and entering the context and the second one is runtime code execution. In the first step variables, function declarations and formal parameters are created. In the second stage function expressions and unqualified identifiers (undeclared variables) are created. However for practical purposes we can adopt the concept of hoisting.

Conclusion

With this post I tried to demystify some of the strange behavior you sometimes may experience. I hope by reading this and applying the concept you can avoid some frustration in the future. Following the best practices will get you a long way, and remember: it’s Javascript, it IS different.

Well what I meant by that is that at the implementation level things are a little bit different. It’s not that the declaration just gets moved and that’s that. It’s just that is a valid assumption to make.

In the section you linked you can see that behind the scenes a lot more is going on than just the move.

http://github.com/rwldrn/tc39-notes Rick Waldron

Yes, I’m very familiar with all of the content at the link I provided you and yes it does specify, step-by-explicit-step, the “hoisting” behaviour that must be adhered to in a conforming implementation. Your post says “The ECMAScript standard does not define hoisting at all.” which is wrong. Your reply here claims “the implementation level things are a little bit different”, which is wrong—if this were true, it would be a bug in the implementation.

I’m not trolling you or trying to embarrass or shame you. As one of jQuery’s representatives to Ecma/TC39, all that I care about is dissemination of factual information. Please stop blowing me off and publish a correction. Thank you

Kenneth Truyers

Hello Rick,
Thanks for your further explanation. I just want to say that I’m not trying to blow you off, nor do I think you’re trolling me. However, I still disagree with your point of view and I think my statement still stands. What I meant to say is that implementation-wise, the variable declaration just doesn’t get moved, there’s other things happening under the hood. From a user’s point of view that is not important since the behavior is the same.
I have edited the particular section to try and explain it better. I hope you can see my point of view and the reason why I added that sidenote (and the reason why I’m sticking with it)

Well written.
You should remove this. from this.mymethod() and this.mysecondmethod() as they produce an error.

Kenneth Truyers

You’re right, I fixed it. Don’t know why I did it like that. Thanks!

Justin

Does this mean things like variable declarations in for loops get hoisted, too? So declaring i in a for loop once will result in it getting hoisted to the top and any subsequent call to i in a for loop under the first one (but not inside) will have the same final value as i? Does that make sense? Guess I could try it out in dev tools, but this is more fun.

Kenneth Truyers

Yes, variables only have function scope, so in a loop they are shared as well:
function something(){
for (var i=0;i<10;i++){}
alert(i); // will alert 10
}

http://setapp.me Elad Ossadon

var myvar; // this is the same as var myvar = undefined;

Not exactly, as redefining a variable which was already assigned before will not assign undefined as value. So it’s more like “if myvar is not allocated, allocate it (with undefined as a value), otherwise, ignore”

a = 1; var a; alert(a)

Kenneth Truyers

In this case it is, since it’s a hoisted variable:var myvar = 1;
function something(){
var myvar;
alert(myvar); // will output "undefined"
}
My point was that if you define it inside a function that it gets hoisted and thus by default set to undefined, hiding the access to any global variables with that name you may have.

Because x is not hoisted. If you don’t declare x with a var-keyword, it will not be hoisted. When it reaches the second line (assuming it does) it just assigns it to a global variable. But because in the first line it tries to print something that doesn’t yet exist, it throws an error.