Global Variables vs Local Variables in JavaScript- Key Differences
What the Hell Is Variable Scope in JavaScript?
Before you can understand the difference between global and local variables, you need to wrap your head around scope. Scope is simply the part of your code where a variable is accessible. That's it. Nothing fancy.
JavaScript has three types of scope:
- Global scope — accessible everywhere in your code
- Function scope — accessible only inside the function where it's declared
- Block scope — accessible only inside the curly braces
{}where it's declared (introduced withletandconst)
Variables declared with var are function-scoped. Variables declared with let and const are block-scoped. This distinction matters more than most tutorials admit.
Global Variables: When Your Data Lives Everywhere
A global variable is declared outside any function. You can access it from anywhere in your code — inside functions, loops, conditionals, other files (if properly exported).
How to Create a Global Variable
Three ways to do this:
// Method 1: Declare outside any function
const appName = "MyApp";
let version = 1.0;
// Method 2: Assign to window object (bad practice, but it works)
window.apiKey = "12345";
// Method 3: Omit let/const/var in non-strict mode (really bad practice)
globalVar = "I exist everywhere";
Method 3 will bite you. In strict mode, it throws an error. In sloppy mode, it creates an accidental global. Don't do it.
When Global Variables Make Sense
Honestly? Rarely. But there are legitimate use cases:
- Constants that never change across your entire application
- Application configuration objects
- State management in small scripts
- Module-level exports in Node.js
The Problem with Global Variables
Global variables create tight coupling. Any function can modify them. Any part of your code can overwrite them. Debugging becomes a nightmare because changes can come from anywhere.
Imagine fifty functions all reading and writing to the same global variable. Which one broke it? Good luck finding out.
Local Variables: Keeping Your Data Contained
A local variable is declared inside a function or block. It only exists within that scope and disappears when the function/block finishes executing.
Function-Scoped Local Variables (var)
function calculateTotal(price, quantity) {
var discount = 0.1; // local to this function
var subtotal = price * quantity;
var total = subtotal - (subtotal * discount);
return total;
}
console.log(discount); // undefined - discount doesn't exist here
Block-Scoped Local Variables (let and const)
function processUser(user) {
if (user.isActive) {
let status = "active"; // only exists inside this if block
const message = "User is online";
console.log(message, status);
}
console.log(status); // ReferenceError - status doesn't exist here
}
The difference between var and let/const is huge. var leaks out of blocks. let and const stay locked in.
Global vs Local Variables: The Key Differences
Here's what separates them:
| Aspect | Global Variables | Local Variables |
|---|---|---|
| Declaration | Outside all functions | Inside functions or blocks |
| Accessibility | Everywhere in the code | Only within declaring scope |
| Lifetime | Until page/script closes | Until function/block ends |
| Memory | Occupies memory longer | Freed after use |
| Risk | Name collisions, unexpected changes | Contained, predictable |
| Testing | Harder to test in isolation | Easier to test |
Scope Chain: How JavaScript Finds Variables
When JavaScript encounters a variable, it searches in this order:
- Current scope — is the variable declared here?
- Parent scope — is it declared in the enclosing function?
- Grandparent scope — keep going up the chain
- Global scope — last resort
- ReferenceError — variable doesn't exist anywhere
const globalVar = "I'm global";
function outer() {
const outerVar = "I'm in outer";
function inner() {
const innerVar = "I'm in inner";
console.log(globalVar); // Found at global scope
console.log(outerVar); // Found at outer scope
console.log(innerVar); // Found at current scope
}
console.log(innerVar); // ReferenceError - innerVar is local to inner()
}
Common Mistakes That Will Ruin Your Code
Mistake #1: Accidental Globals
function badExample() {
result = 10; // Oops - no var/let/const
// This creates a global variable!
}
badExample();
console.log(result); // 10 - result is now global
Always declare your variables. Always.
Mistake #2: Shadowing
let count = 0; // global
function increment() {
let count = 10; // This is a NEW local variable, not the global one
count++;
console.log(count); // 11
}
increment();
console.log(count); // 0 - global count is unchanged
The local count shadows the global count. They are completely separate variables.
Mistake #3: Relying on Hoisting
function broken() {
console.log(value); // undefined (hoisted but not assigned)
var value = 100;
console.log(value); // 100
}
var declarations get hoisted to the top of their function. The variable exists, but it has no value yet. This causes bugs that are hard to track down.
Practical How-To: Choosing the Right Variable Type
Here's a decision tree you can actually use:
- Need the value everywhere? → Global constant (use
const) - Need to share state between functions? → Pass as parameter or use a module pattern
- Only used inside one function? → Local variable with
constorlet - Only used inside one block (if/loop)? → Use
letorconst - Old code using var? → Refactor when you get the chance
Modern Module Pattern Example
// Instead of polluting global scope:
const AppState = (function() {
// Private variables - truly local
let count = 0;
let users = [];
// Public API
return {
increment: () => count++,
getCount: () => count,
addUser: (user) => users.push(user),
getUsers: () => [...users] // return copy, not reference
};
})();
AppState.increment();
console.log(AppState.getCount()); // 1
console.log(count); // ReferenceError - count is private
This pattern keeps variables local to an IIFE while exposing only what you need. No globals, clean API.
ES6+ Best Practices
If you're writing JavaScript in 2024 and still using var for everything, stop. Here's what you should do:
- Use
constby default — values that don't change - Use
letwhen you need to reassign — loop counters, accumulators - Avoid
var— it has weird hoisting behavior and function scope causes bugs - Keep global variables to an absolute minimum
- Use modules (
import/export) instead of global namespace pollution
// Modern approach - no globals needed
// file: config.js
export const API_URL = "https://api.example.com";
export const TIMEOUT = 5000;
// file: app.js
import { API_URL, TIMEOUT } from './config.js';
fetch(API_URL, { timeout: TIMEOUT });
Modules give you encapsulation without globals. Use them.
Quick Reference
| Keyword | Scope | Hoisting | Reassignment |
|---|---|---|---|
var |
Function | Declaration hoisted, value is not | Allowed |
let |
Block | Temporal dead zone (can't access before declaration) | Allowed |
const |
Block | Temporal dead zone | Not allowed (but object properties can change) |
The Bottom Line
Global variables are not evil, but they're overused by beginners who don't understand scope. Local variables keep your code predictable and testable. The rule is simple: declare variables with the smallest scope possible. If you need data in multiple places, pass it as a parameter or use ES6 modules.
Most bugs I see in JavaScript code come from too many globals and var keyword confusion. Fix those two things and your code quality improves immediately.