Skip to content

Scope And Hoisting

JavaScript is an extremely flexible and powerful language, but understanding its internal behavior can sometimes be tricky. Let’s take a closer look at two fundamental concepts: Scope and Hoisting.


Scope determines the accessibility of variables in different parts of the program. JavaScript supports two main types of scope:

  • Global Scope: Variables declared outside of any function body belong to the global scope. They can be accessed and modified anywhere in the code.

  • Block Scope: Introduced with ES6, variables declared using let or const have block scope. This means they are accessible only within the surrounding curly braces {}.

{
let blockScoped = "I exist only in this block!";
console.log(blockScoped); // This works
}
console.log(blockScoped); // ReferenceError: blockScoped is not defined

In contrast, variables declared with var are not block-scoped, which can often lead to unexpected results.


Hoisting is JavaScript’s default behavior of moving variable and function declarations to the top of their respective scopes during the compilation phase.

Variables declared with var are hoisted, but their values are not initialized until the code execution reaches the declaration.

console.log(hoistedVar); // undefined var hoistedVar = "I was hoisted!"; console.log(hoistedVar); // "I was hoisted!"

Variables declared with let and const are also hoisted, but they are placed in a “temporal dead zone” from the start of the block until the declaration.

console.log(blockScopedVar); // ReferenceError: Cannot access 'blockScopedVar' before initialization
let blockScopedVar = "This won't work with let or const!";

Functions declared using the function keyword are hoisted, and their definition is available for use before they are defined in the code.

sayHello();
function sayHello() {
console.log("Hello, Hoisting!");
}

However, functions assigned to variables (using var, let, or const) are not fully hoisted. They behave like variables being assigned to function expressions.


this holds a reference to the execution context, which depends on how the function is called.

The value of this depends on where the function is called.

function regularFunction() {
console.log(this);
}
regularFunction(); // In non-strict mode: global object (e.g., `window`) // In strict mode: undefined

Arrow functions do not have their own this; instead, they inherit it from their surrounding scope.

const obj = {
arrowFunction: () => {
console.log(this);
},
};
obj.arrowFunction(); // Inherits `this` from the surrounding scope

Understanding these concepts—Scope, Hoisting, and the behavior of this—is critical to writing maintainable and bug-free JavaScript code.