JavaScript Variable Scope


In JavaScript, variable scope defines the accessibility of variables in different parts of your code. Whether a variable can be accessed or modified depends on where it is declared. Understanding scope is critical for writing clean, error-free code and avoiding issues like variable collisions and unintended side effects.


1. What is Variable Scope?

Variable scope refers to the context in which a variable is declared and determines where it can be accessed or modified. In JavaScript, there are several levels of scope:

  • Global Scope: Variables declared outside any function or block are in the global scope and are accessible throughout the entire code.
  • Local Scope: Variables declared within a function or block are in the local scope and can only be accessed within that function or block.
  • Block Scope: Variables declared with let or const within a block {} are scoped to that block and not accessible outside it.

2. Global Scope

A variable declared outside of any function or block has global scope. Global variables are accessible throughout the entire code, which can lead to potential issues if the variable name conflicts with another variable later in the program.

Example 1: Global Scope

let globalVar = "I am a global variable";

function printGlobalVar() {
  console.log(globalVar); // Accesses the global variable
}

printGlobalVar(); // Output: I am a global variable
console.log(globalVar); // Output: I am a global variable

Explanation:

  • The variable globalVar is declared outside of any function, so it has global scope.
  • It is accessible both inside the printGlobalVar() function and in the global context.

3. Local Scope (Function Scope)

Variables declared inside a function have local scope. These variables are only accessible within the function they are declared in and are not available outside of it.

Example 2: Local Scope

function localScopeExample() {
  let localVar = "I am a local variable";
  console.log(localVar); // Output: I am a local variable
}

localScopeExample();
console.log(localVar); // Error: localVar is not defined

Explanation:

  • The variable localVar is declared inside the localScopeExample function.
  • It is accessible inside the function but not outside of it, leading to an error when we try to access it in the global scope.

4. Block Scope (Let and Const)

With block scope, variables declared with let or const are scoped to the block they are defined in. This means they are only accessible within the curly braces {} that define the block, whether inside a function, an if statement, or a loop.

Example 3: Block Scope with let and const

if (true) {
  let blockScopedVar = "I am block scoped";
  const anotherBlockScopedVar = "I am also block scoped";
  console.log(blockScopedVar); // Output: I am block scoped
  console.log(anotherBlockScopedVar); // Output: I am also block scoped
}

console.log(blockScopedVar); // Error: blockScopedVar is not defined
console.log(anotherBlockScopedVar); // Error: anotherBlockScopedVar is not defined

Explanation:

  • Both blockScopedVar and anotherBlockScopedVar are declared within the if block.
  • They are only accessible inside the block and not in the global scope or outside the block where they are declared.

5. Function Scope with var

Variables declared with var have function scope. This means that even if you declare a variable inside a block (such as an if statement), it is still accessible throughout the entire function in which it is declared. However, var is hoisted, meaning it is moved to the top of the function scope during the execution of the code.

Example 4: Function Scope with var

function functionScopeExample() {
  if (true) {
    var functionScopedVar = "I am function scoped";
  }
  console.log(functionScopedVar); // Output: I am function scoped
}

functionScopeExample();

Explanation:

  • The functionScopedVar is declared inside the if block but is accessible outside of it within the same function because var does not have block scope.
  • It is available throughout the entire functionScopeExample function due to function scoping.

6. Hoisting in JavaScript

Hoisting is a behavior in JavaScript where variable and function declarations are moved to the top of their containing scope during the execution phase. This affects var-declared variables, which are hoisted but not initialized, and function declarations, which are hoisted with both their declaration and initialization.

Example 5: Hoisting with var

console.log(hoistedVar); // Output: undefined
var hoistedVar = "I am hoisted";
console.log(hoistedVar); // Output: I am hoisted

Explanation:

  • The declaration var hoistedVar is hoisted to the top, but the assignment "I am hoisted" is not.
  • Therefore, the first console.log(hoistedVar) outputs undefined because the variable has been declared but not yet assigned a value.

Example 6: Hoisting with Functions

greet(); // Output: Hello, world!

function greet() {
  console.log("Hello, world!");
}

Explanation:

  • The greet() function is hoisted, so you can call it before its actual definition in the code.
  • This is possible because function declarations are hoisted with their definition.

7. Lexical Scope (Closures)

Lexical scope refers to the fact that a function’s scope is determined by where it is defined, not where it is called. This is particularly important when dealing with closures—functions that "remember" their lexical environment.

Example 7: Lexical Scope and Closures

function outerFunction() {
  let outerVar = "I am from the outer function";

  function innerFunction() {
    console.log(outerVar); // Accesses outerVar from the outer function's scope
  }

  innerFunction();
}

outerFunction(); // Output: I am from the outer function

Explanation:

  • The innerFunction() has access to variables from its outer function (outerFunction()), even though outerFunction() has finished execution.
  • This is an example of a closure in JavaScript, where the inner function "remembers" the scope in which it was created.