Fork me on GitHub

James Allardice

Assorted thoughts of a web developer

Welcome!

James Allardice

I'm a young, enthusiastic web developer with a passion for front-end development with HTML5, JavaScript and jQuery. I spend a lot of my free time over at Stack Overflow where I enjoy helping out others with problems relating to the above technologies. I doubt I'll post here all the time, but I will try my best to ensure the things I do post are useful and interesting to anyone who may stumble across them!

I'm always on the lookout for exciting opportunities so if you have something that you think qualifies as such don't hesitate to get in touch.


Explaining function and variable hoisting in JavaScript

Perhaps one of the most potentially confusing aspects of JavaScript is its scoping mechanism. If you don't fully understand what's going on, you can easily run into all sorts of difficulties. Key to understanding how scope in JavaScript works is understanding the concept of hoisting.

Let's jump straight in with an example:

var x = 10;
function y() {
    console.log(x); //Prints undefined
    var x = 20;
    console.log(x); //Prints 20
}
y();
console.log(x); //Prints 10

On the first line in that snippet we declare a variable, x, and assign it the value 10. We then define a function, in which we try and output the value of x. If you understand the basics of scope in JavaScript then you should be well aware that variables declared in the parent scope of a function are accessible inside that function. Going by that logic, it could fairly be assumed that the first console.log statement would print 10, since that's what we assigned to x just before we called the function.

However, the second line of that function body causes things to change. If you remove that line, the first console.log call does indeed print 10. So, why does that line affect us in this way? Well, variable declarations in JavaScript are hoisted to the top of their scope. That means the above snippet is effectively interpreted like this:

var x; //Declaration of x is hoisted (x is undefined)
x = 10; //Assignment still occurs where we intended (x is 10)
function y() {
    var x; //Declaration of a different variable named x is hoisted (x is undefined)
    console.log(x); //Prints undefined
    x = 20; //Assignment (x is 20)
    console.log(x); //Prints 20
}
y();
console.log(x); //The variable named x in the outer scope still contains 10

That simple example should be enough to demonstrate the concept of hoisting as it applies to variable declarations. A couple of important point to remember.

First, we only observe the "strange" behaviour in the above snippet because we've declared a new variable with the same name as one in an outer scope. The new variable shadows the other so we see undefined as the output of the second log.

Second is that it's the declaration itself that gets hoisted, not the assignment. Assignments will happen at the point you expect when you write them. That's particularly important to bear in mind as we move on to look at function hoisting.

With functions, the concept is the same. That is, function declarations are hoisted to the top of the scope in which they are defined. This means it's possible to call a function before it's actually been declared in your code. For example:

sayHello(); //Calling the function before it's been declared
function sayHello() {
    console.log("Hi!");
}

Again, that should be pretty self explanatory if you've followed the article this far. The function declaration, including the function body, is hoisted to the top of its scope, so it's available on the first line of our example to be called.

Now remember that important second point when we were talking about variable hoisting. As I'm sure you're aware, JavaScript has function expressions, as well as the function declarations mentioned above:

sayHello(); //Uh-oh... TypeError, undefined is not a function!
var sayHello = function() {
    console.log("Hi!");
};

So why did that last example fail? If you think about it, it's quite obvious really. We know that variable declarations are hoisted, and we know that function declarations are hoisted. A function expression is effectively a variable declaration and an assignment. The variable declaration is hoisted, but the assignment stays where it is, resulting in something like this:

var sayHello;
sayHello(); //Uh-oh... TypeError, undefined is not a function!
sayHello = function() {
    console.log("Hi!");
};

And that's pretty much all there is to it! If you've made it to the end of this article you should have a decent understanding of how JavaScript hoists variable and function declarations and will be able to quickly eliminate that next time you run into an awkward scoping bug in your code.

comments powered by Disqus

Tags

Latest Tweets


Copyright © 2012 James Allardice