Scoping and Hoisting in Javascript

For you to be a good Javascript developer, knowing how javascript works behind the scene is very important this is because it decreases the time spent in debugging.

What is Scoping?

Scoping is determining how variables are organized and accessible by the javascript engine. Variables are containers that are used to store values. In javascript, variables were declared with the var keyword prior to Es6 although let and const keywords are used to decrease errors, to figure out why keep reading. Scope is quite different from scoping. Scope is a space or environment where variables are declared. There are three types of scope

  1. Global scope
  2. Function scope/ local scope
  3. Block scope (started in Es6)

    Global scope:

    They are for variables that are not declared in functions. They are top level codes and are accessible everywhere both in functions and blocks.

    Function scope:

    Each and every function creates a scope and the variables created in that function are only accessible within the function.

    Block scope:

    Just like the function scope, every variable declared within a block scope is only accessible within the block scope. Only let and const variables are restricted to block scope while var variables are function scoped.

    Scoping in Practice

    // Global scope
    const firstName = 'james';
    var lastName = 'Jockberg';
    let birthAge = 23;
    
    The function below calculates the hours spent in a work by logging in the time you arrived and the time you are going.
    // function scope
    const timeSpent = function (start) {
    var result = 18 - start;
    return result;
    };
    console.log(timeSpent(8));
    console.log(result);
    
    When result is log in the console, it gives an error

Untitled-function scope.png

// block scope
const kpeale = {
  realName: 'jane',
  age: 22,
  hasDriverLicense: true,
};

if (kpeale.hasDriverLicense) {
  const teacherName = 'Jonas';
  console.log(
    `Yesss!! ${kpeale.realName} is ${kpeale.age} so she should have a license which was verified by ${teacherName} `
  );
} else {
  console.log(
    `${kpeale.realName} is ${kpeale.age}. she is not up to age for a license `
  );
}
console.log(teacherName)

When the variable teacherName is logged in the console, it gives an error

Untitled-block scope.png

// block scope
const kpeale = {
  realName: 'jane',
  age: 22,
  hasDriverLicense: true,
};

if (kpeale.hasDriverLicense) {
  var teacherName = 'Jonas';
  console.log(
    `Yesss!! ${kpeale.realName} is ${kpeale.age} so she should have a license which was verified by ${teacherName} `
  );
} else {
  console.log(
    `${kpeale.realName} is ${kpeale.age}. she is not up to age for a license `
  );
}
console.log(teacherName)

but does not give an error when created with var keyword, instead it gives Jonas which is the value of the variable. Untitled-var.png

Hoisting

This is another confusing concept in Javascript because Hoisting is defined in Javascript as the movement of variables and function declarations magically to the top of their scope so they can be used before declaring them which is false. What happens is that when a piece of code is executed, the Javascript engines creates the global execution context for top level codes- codes that are not inside a function and the execution context. The execution context contains:

  • Variable environments
  • Scope chain
  • This keyword.

The above components are all created in the creation phase, in the creation of the variable environment, variables and function declarations are moved to the top of their scope. This is known as hoisting, the movement of variables and function declarations to the top of their scope making it possible to be accessible before declared in the code. It is important to note that hoisting does not work for all variable types and we will look at them in this article. How hoisting works with:

  • Function declarations
  • Var variables
  • Let and const variables
  • Function expressions and arrow functions

    Hoisting with function declarations:

    One of the advantage of using function declarations over function expressions is you can use them before declaring them in the code. This means that hoisting works with them but why is it so? Function declarations are actually hoisted and the initial value in the variable is set to the actual function. This means the reason behind using them before declaring them in the code is due to variable being stored in the variable environment before execution.

    Hoisting with var variables:

    They are also hoisted but in a different way. If we try to access a var variable before it is declared in the code, we get undefined. Which is a weird error and that is why it is advised to use const and let keywords in making variables than var because var is prone to cause bugs in codes. Untitled-undefined.png

    Hoisting with let and const variables:

    They are not hoisted. Their value is set to an initialized so there is no value to work at all making it look as if there is no hoisting at all. Instead, we say that the variables are placed in a TDZ-temporal dead zone making it impossible to access the variable between the beginning of the scope to the place where the variables are declared. Untitled-var and const.png

    Temporal Dead Zone

    This is the region before a variable is declared. It is as if the variables didn’t exist if we try to access this variable in the TDZ, we will get a reference error. Reference error: Cannot access ‘variable’ before initialization.
    Reasons for TDZ
  • It makes it easier to catch bug errors.
  • Accessing errors before declaration is a bad practice and should be avoided so the aim of TDZ is to prevent you from accessing variables before declaration. Untitled-TDZ.png

    Hoisting with function expressions and arrows

    It depends on what keywords was used to create them. This is because these functions are simply variables so they behave like variables in regards to hoisting. This means a function expression or arrow function created with var is hoisted to undefined while with let or const will produce an error because of TDZ unless accessed after declaration. In conclusion: Avoid accessing your variables before declaration, this is because it is a bad practice instead write all your variables at the top of your code to prevent bugs.