he JavaScript concepts of Scoping and Hoisting are easy to understand and work with when writing simple scripts.

Scoping and Hoisting can be confusing, however, when writing larger amounts of JavaScript code involving numerous functions, data structures, and data types.

> Let's make the concepts of Scope and Hoisting in JavaScript as simple as possible.

Take a look at the code block below:

var x;    // declare our variable

function foo() {
  console.log(x);
  x = 5;  // initialize our variable
}

// call our new foo function
foo();

In the sample code above, can you guess the result of calling foo()? If you guessed undefined, then you are right! Read on to find out exactly why undefined is the answer.

What is JavaScript Scope?

Scope in JavaScript simply means “where an element, data, or value is usable” in the script. In JavaScript, we have two kinds of scope:

  • Global scope
  • Local scope

For instance:

var x = 5;    // declare x globally

function foo() {
  var x = 4;      // create x locally in the function
  console.log(x); // logs 4
}

foo();          // call our function

console.log(x); // logs 5

Note: Creating a new function creates a new local scope called function scope.

In the code block above we have the basic representation of the global scope and the function (local) scope. x is declared and initialized with the value of 5 which is available to the global scope and is accessible anywhere in the script.

In the function foo() x is re-declared and initialized while assigning it a value of 4. Local variables like the var x = 4 inside our function are created when the function starts and deleted when the function is run.

x is independent of the global scope and is only accessible within the function foo(). Once a variable is declared with var it can be used anywhere in the code retaining its original value unless re-assigned a new value:

var x = 10;     // declare x

function foo() {
  x = 20;       // reassign the global x to 20
}

foo()           // call our function

console.log(x); // 20

A Common Scope Gotcha

It's very common to assume that variables are block scoped. While there is function scope, block scope would be things like:

  • if statements
  • for...of statements
  • foreach statements
  • normal blocks {}

Before ES6 and the introduction of let and const, variables were scoped only to functions and the global. This means code inside {} does not necessarily have a local scope. Functions do have a local scope, but if and for do not.

The below example does not have a local scope. Creating a var inside of an if will create a global variable.

if (true) {
  var foo = 5;
}

console.log(foo);   // 5

Your instincts might have told you that the value of 5 outside the if statement is undefined. Since if doesn't have a local scope, the var foo = 5; is created globally.

Be watchful of such situations. This can be alleviated with the let statement as that creates the variable within the current block.

Using let to Block Scope

With the introduction of the let keyword to declare variables in ES6, we have an easier way to understand where our variables live in the overall terms of our code.

Using let, we can declare the same variable name multiple times and be sure of what the scope is. Let's take the two examples below comparing the var and let methods.

Using var

function doSomethingCool() {
  var x = 5;    // variable scoped to doSomethingCool() function

  if (true) {
    var x = 10;      // same variable! will override the x=5
    console.log(x);  // logs 10 
  }

  console.log(x);    // logs 10
}

Using let

function doSomethingCool() {
  let x = 5;    // variable scoped to doSomethingCool() function

  if (true) {
    let x = 10;      // new variable! does not conflict with x=5
    console.log(x);  // logs 10 
  }

  console.log(x);    // logs 5
}

Conclusion

Scoping in JavaScript have always been one source of confusion for JavaScript beginners, in this article we have been able to emphasize the relevance of positioning variable declarations and initializations in order to have them usable in scope. These go hand in hand with helping the debug process of code blocks easier. You can read more on about this topic on the Scotch Blog.

Chris Nwamba

49 posts

JavaScript Preacher. Building the web with the JS community.