JavaScript Function Scope Local vs Global Scope

Local scope keeps variables inside functions. Global scope makes them visible everywhere. Learn where each variable lives, why it matters, and how to avoid accidental global pollution.

6 min read

Scope is the rule that determines where a variable is visible and where it is not. If you declare a variable inside a function, code outside that function cannot see it. If you declare it outside any function, every function can see it. That is the core difference between local and global scope.

javascriptjavascript
const globalMessage = "I am visible everywhere";
 
function showMessage() {
  const localMessage = "I am only visible inside this function";
 
  console.log(globalMessage); // Works: global is visible here
  console.log(localMessage);  // Works: local is in scope
}
 
showMessage();
console.log(globalMessage);   // Works
console.log(localMessage);    // ReferenceError: localMessage is not defined

globalMessage is declared in the top-level scope. Every function can access it. localMessage is declared inside showMessage. Only code inside that function can see it.

How Scope Nesting Works

Scope in JavaScript is hierarchical. Inner scopes can see outer scopes, but outer scopes cannot see inner scopes:

Scope visibility chain

Think of it like one-way glass. Code inside a function can look out and see global variables. Code outside cannot look in and see function variables.

javascriptjavascript
const outer = "I am outside";
 
function middle() {
  const inner = "I am inside middle";
 
  function deepest() {
    console.log(outer); // Works: looking outward through the scope chain
    console.log(inner); // Works: looking one level up
  }
 
  deepest();
}

Calling middle triggers deepest, which can see both its own parent's variable and the outer global one. But the reverse is not possible, code outside deepest has no way to reach into it:

javascriptjavascript
middle();
console.log(outer); // Works
// console.log(deepestVar) would fail -- cannot look into deepest

Global Scope

A variable has global scope when it is declared outside any function or block. In browsers, global variables become properties of the window object. In Node.js, they are properties of the global object.

javascriptjavascript
// Global scope -- visible everywhere
const API_URL = "https://api.example.com";
let currentUser = null;
 
function login(user) {
  currentUser = user; // Accessing global variable
}
 
function getApiUrl() {
  return API_URL; // Accessing global constant
}

Global constants like API_URL are generally fine. Global mutable state like currentUser is risky, any function can change it, making bugs hard to trace.

Local (Function) Scope

Every function creates its own local scope. Parameters and variables declared inside the function belong to that scope:

javascriptjavascript
function calculateTotal(price, quantity) {
  // price and quantity are local (parameters)
  const tax = 0.08;       // local variable
  const total = price * quantity * (1 + tax); // local variable
  return total;
}
 
console.log(tax); // ReferenceError: tax is not defined

Parameters count as local variables. They exist only for the duration of the function call, and once the function returns, that entire local scope, tax included, is gone and unreachable from anywhere else.

var vs let vs const in Scope

var is function-scoped. let and const are block-scoped. This difference matters inside blocks like if statements and loops:

javascriptjavascript
function testVar() {
  if (true) {
    var x = "var is function-scoped";
  }
  console.log(x); // "var is function-scoped" -- still visible!
}
 
function testLet() {
  if (true) {
    let y = "let is block-scoped";
  }
  console.log(y); // ReferenceError: y is not defined
}

With var, the variable leaks out of the if block because var only cares about function boundaries. With let and const, the curly braces create a hard boundary.

varlet / const
Scope boundaryNearest functionNearest block ({})
Visible outside an if or loop blockYesNo
Typical resultAccidental leakageContained, predictable

This is why let and const are preferred. They scope variables to the smallest reasonable container, reducing accidental leakage. For more, see JavaScript Variable Naming Conventions Rules.

The Problem with Too Many Globals

Global variables create risks that grow with the size of the codebase, since every additional file that can read or write a global is another place a bug could originate from:

  • Naming collisions: two scripts use the same variable name and overwrite each other.
  • Accidental mutation: any function can change any global, making bugs hard to trace.
  • Testability: global state must be set up and torn down between tests.
  • Readability: you cannot tell where a global variable is modified just by reading one function.
javascriptjavascript
// Risky: global mutable state
let cart = [];
 
function addToCart(item) {
  cart.push(item); // Any function could also modify cart
}
 
function clearCart() {
  cart = []; // Another global mutation
}

A better approach is to pass state explicitly or use closures, so the data lives inside a function scope instead of sitting in the global namespace where anything can reach it:

javascriptjavascript
function createCart() {
  const items = []; // Private, not global
 
  return {
    add(item) { items.push(item); },
    getAll() { return [...items]; },
    clear() { items.length = 0; },
  };
}
 
const cart = createCart();
cart.add("Book");
console.log(cart.getAll()); // ["Book"]

The items array is completely private. No other code can touch it. For more on this pattern, see Returning Functions from Functions in JavaScript.

Rune AI

Rune AI

Key Insights

  • Local scope: variables declared inside a function are only visible inside that function.
  • Global scope: variables declared outside any function are visible everywhere.
  • var is function-scoped. let and const are block-scoped.
  • Functions can see variables from their outer scopes, but outer scopes cannot see into functions.
  • Keep variables as local as possible to avoid naming collisions and accidental mutations.
RunePowered by Rune AI

Frequently Asked Questions

Should I ever use global variables?

Rarely. Global variables are fine for small scripts or configuration constants that truly need to be accessed everywhere. For anything larger, wrap your code in functions or modules to keep variables local.

What is the difference between function scope and block scope?

Function scope means a variable declared with var is visible throughout the entire function, even before its declaration line. Block scope (with let and const) means the variable is only visible inside the nearest set of curly braces {}.

Do modules have their own scope?

Yes. ES modules create their own scope. Variables declared at the top level of a module are not global -- they are module-scoped. You must explicitly export them for other modules to access.

Conclusion

Scope is the set of rules that determines where a variable is visible. Local scope keeps variables contained inside functions or blocks. Global scope makes them visible everywhere. The key skill is knowing where your variables live and keeping them as local as possible to avoid conflicts, bugs, and maintenance headaches.