JavaScript Hoisting Variable Scope Explained

Introduction

What is hoisting? What is variable scope? How does JavaScript hoisting and variable scope work?  This post will explain how hoisting works in JavaScript. Before understanding how hoisting works, developers need to understand variable scope in JavaScript. This article will guide readers and explain the basics of how variable scopes work in JavaScript. 

Hoisting is one of the misunderstood parts of JavaScript. Developers from a traditional class-based object-oriented programming language find it confusing. Fully understanding the fundamentals will make you a better developer. I highly recommend readers to invest time in strengthening their fundamentals: it pays dividends in the future! 

I intend to write posts on each fundamental concept in JavaScript. Please feel free to reach out if you have any questions, feedback or suggestions. They are highly appreciated 🙂

JavaScript Variable Scope – An Introduction

In JavaScript, variables can return unexpected results if developers write code without understanding how variable scopes and hoisting works.  There are primarily two scopes: the global and local scope Variables when declared are set to the default value of undefined. Let us take a look at the following code.

function logUndefined() { 
    console.log(numberTen); // Logs undefined 
    var numberTen = 10;
    console.log("This time, it is not undefined: " + numberTen); // Logs 10  
}
logUndefined();
function resultsInError() { 
    console.log(numberTen); // Console will log error: variable never declared. 
} 
resultsInError();

In the code above, when we execute the function logUndefined(),  the value undefined will be logged onto the console. By default, when a variable is declared, its default value is undefined. If a variable is declared, the variable will be hoisted to the top. Take a look at the code below and compare it with the snippet above.

function logUndefined() { 
    var numberTen = undefined;    // Behaves like this thanks to variable hoisting. 
    console.log(numberTen);       // Logs undefined 
    var numberTen = 10;
    console.log("This time, it is not undefined: " + numberTen); // Logs 10  
}
variable-hoisting-javascript

Variable declaration is hoisted and set to undefined.

Okay I think I understand hoisting. And?

There are a couple of gotchas regarding hoisting. Sometimes, hoisting does not work as expected. In this section, we will go through a few common cases. It is often recommended to declare variables at the top of a function. This will ensure that variable hoisting will not create nasty side effects. Understanding how variable scope works in JavaScript earlier on will save you from a lot of headaches.

Case 1: Inside an IIFE (Immediately Invoked Function Expression)

An IIFE is a very common function declaration pattern in JavaScript. In the code below, the function is invoked immediately after it is declared. Try guessing whether the variable declared in the code below is part of global scope or not? A subtle hint was provided two sentences prior to the current one.

(function() {
    var whichScope = 10; // Is it Global?
})();

Answer: var whichScope is not in the global variable. In JavaScript, variables have function scope. This means that variables are local to the function it is declared in. If not defined inside of a function, it will be part of the global scope.

Case 2: Variable Declared in Both Local Function and Global scope

If variables are declared in both the global and local scope, the local scope variable will overwrite the global variable. However, once the function returns to the global scope, the variable name will point to the instance in the global scope.

var name = "I am global rawrrrr";

function localName() {
    var name = "Name in local";
    console.log(name);                  // "Name in local scope"
}

localName();
    
console.log(name);                      // "I am global rawrrrr"

Case 3: Variable declared without the var keyword

This is important. Variables declared without the var keyword will be added to the global scope. Essentially, we are querying the JavaScript engine and asking, “do we have a variable named <variable_name>?” If the answer is no, because we have omitted the var keyword, the JavaScript engine will automatically add the value stored in the variable onto the global scope. This is another source of unexpected behavior. While not directly related to hoisting, I thought it would be important to point it out.

var name = "Global name Bob";

function localName() {
    name = "Local name John";           // accidental omission of var keyword
    console.log(name);                  // prints "Local name John"
    withoutVar = 5;
    console.log(withoutVar);            // Prints 5
}

localName();

console.log(name);                      // Overwritten by assignment in localName()
console.log(withoutVar);                // prints 5. Not printing undefined ... What??? I thought variables are hoisted??

Two nasty side effects exist in the example above.

  1. var name, declared in the global scope was overwritten on line 4.
  2. The global variable withoutVar was accidentally declared on line 6.

Omitting the var keyword inside a function can create some nasty bugs. These bugs become more difficult to find as the application increases in size.

Case 4: Variable declared within curly brackets ( {} )

This brings us to a very important point. JavaScript variables are not block-scoped, but rather, they are function scoped. Examine the code snippet below. No doubt, this will be a source of grief for developers coming from a language that supports block scopes such as C++.

function testScope() {

    var localVar = 5;
    console.log(insideIf);          // prints undefined. Remember hoisting!
    var counter = 1;

    while (counter--) {             // Runs once because of type coercion in JS. 0 is a falsy value.
        var insideWhile = 20;       // prints 10. Surprised?
    }

    if (true) {
        var insideIf = 10;
    }

    console.log(insideWhile);
    console.log(insideIf);          // prints 10. Doubly surprised??
}

testScope();
// Uncaught ReferenceError: insideWhile is not defined
console.log(insideWhile);           // JS variables are NOT block scoped. They are function scoped!!!!

In conclusion

In summary, the key points for this post are the following

  • Variables when declared in the middle of a function act as if it is initialized at the start with undefined assigned to it. When it is actually declared I.E.var someValue = 10; is set to something other than undefined.
  • Declare variables at the top of a function. At the very least, declare it before it is used. This will prevent nasty bugs in the future.
  • Remember to include the var keyword when declaring variables.
  • JavaScript variables declared with var has function scope. If you want block scoping, use let.

Additional Resource

Having access to good results is crucial. Below, I have added resources that helped me learn. As a bonus, I will also throw in my personal feedback. I will post up additional resources upon request.

Kyle Simpson: Scopes and Closures

This book is part of a book series called You Don’t Know JS. I highly recommend every JavaScript developer to read it! Kyle Simpson provides excellent insight into how variable scope and hoisting works. I personally learnt a lot from his books and workshops on Frontend Masters.

JavaScript – The Good Parts By Doug Crockford

JavaScript: The Good Parts is a must-read for any JavaScript developer! Despite being relatively old, it is very rich in content. The information is still relevant even after more than a decade. I accredit this book for taking my JavaScript skills to the next level. It packs all the good parts of JavaScript for journeymen developers. Junior developers will also benefit but may find the content quite challenging.

There are other great resources that helped me. However, the list will become too long if I listed them all. Later on, I might make a list of all the recommended resources for each language. Thank you for reading and happy coding!

About the Author Jay

I am a programmer currently living in Seoul, South Korea. I created this blog as an outlet to express what I know / have been learning in text form for retaining knowledge and also to hopefully help the wider community. I am passionate about data structures and algorithms. The back-end and databases is where my heart is at.

follow me on:
1 Shares