Question
JavaScript Variable Scope: Global, Function, and Block Scope
Question
What is the scope of variables in JavaScript? Do variables declared inside a function have the same scope as variables declared outside it? Does the declaration location matter? Also, where are variables stored when they are declared globally?
Short Answer
You will learn how JavaScript decides where a variable can be accessed, how function and block boundaries affect visibility, and why global variables should be used carefully. You will also understand the difference between a global binding and a property on the browser's global object.
Concept
Variable scope is the part of a program where a variable name is available. JavaScript uses lexical scope, meaning scope is determined by where code is written, not by where a function is called.
The main scopes are:
- Global scope: declared outside functions and blocks. It can be accessed by code in the same script or module, subject to module rules.
- Function scope: variables declared with
var,let, orconstinside a function are available only in that function and its nested functions. - Block scope: variables declared with
letandconstinside{}are available only inside that block. Blocks occur inif,for,while, and similar statements. - Module scope: top-level declarations in an ES module belong to that module, not to every script on the page.
An inner scope can read variables from its outer scopes. An outer scope cannot directly read variables declared in an inner scope. This protects local details, prevents accidental name conflicts, and makes functions easier to understand.
const siteName = "Docs"; // global scope
function showPage() {
const pageName = "Scope"; // function scope
console.log(siteName); // works: inner code can read outer variables
console.log(pageName); // works
}
showPage();
console.log(siteName); // works
// console.log(pageName); // ReferenceError: pageName is not defined
Mental Model
Think of scope as nested rooms in a building.
- A global variable is a notice in the building lobby. People in rooms can read it.
- A function variable is a note inside one room. People outside that room cannot see it.
- A block-scoped variable is a note inside a smaller locked area within the room.
Code inside a room can look outward through the building for a name. It cannot look into a different room or a locked inner area.
Syntax and Examples
Declare variables with const by default, let when reassignment is needed, and avoid var in new code unless maintaining older code.
const appName = "Task List"; // global scope
function createTask(title) {
const status = "open"; // function scope
if (title.length > 0) {
const message = `Created: ${title}`; // block scope
console.log(message);
}
console.log(status);
}
createTask("Buy milk");
console.log(appName);
// console.log(status); // Error: status is only inside createTask
// console.log(message); // Error: message is only inside the if block
Here, appName is declared outside the function, so createTask can read it. status exists for the entire call. exists only while execution is inside the block.
Step by Step Execution
Consider this code:
const currency = "USD";
function formatPrice(price) {
const label = "Price";
if (price > 0) {
const formatted = `${label}: ${price} ${currency}`;
return formatted;
}
return "Invalid price";
}
console.log(formatPrice(25));
Execution steps:
- JavaScript creates the global
currencybinding with the value"USD". - JavaScript stores the
formatPricefunction so it can be called later. formatPrice(25)creates a new function scope for this call. Itspriceparameter is25.labelis created inside the function scope.- The condition
price > 0is true, so JavaScript enters the block.
Real World Use Cases
- Configuration: an application may keep a small amount of shared configuration, such as an API base URL, in module-level scope.
- Function parameters: a validation function keeps input values local so unrelated code cannot change them.
- Loop variables:
letcreates a block-scoped loop variable, which helps event handlers keep the correct value. - Temporary values: calculations inside an
ifblock can use local variables without exposing them to the rest of the function. - Reusable modules: a module can keep helper functions and internal state private while exporting only its public API.
function isValidEmail(email) {
const hasAtSign = email.includes("@");
return hasAtSign;
}
console.log(isValidEmail("sam@example.com"));
// hasAtSign is not accessible here
Real Codebase Usage
Developers use scope to limit what each part of a program can access.
Prefer local variables
Keep a value in the smallest scope that needs it.
function calculateTotal(items) {
let total = 0;
for (const item of items) {
total += item.price;
}
return total;
}
Use guard clauses
A guard clause returns early when input is invalid. Variables stay local to the function.
function getDisplayName(user) {
if (!user) {
return "Guest";
}
return user.name;
}
Keep module internals private
In an ES module, only exported names are intended for other files to use.
const defaultTimeout = 5000;
export function requestOptions() {
return { timeout: defaultTimeout };
}
Common Mistakes
Expecting a local variable outside its function
function greet() {
const message = "Hello";
}
// console.log(message); // ReferenceError
Declare the variable outside the function only if multiple parts of the program genuinely need it. Otherwise, return the value.
function greet() {
return "Hello";
}
console.log(greet());
Using var when block scope is intended
var is function-scoped, not block-scoped.
if (true) {
var userRole = "admin";
}
console.log(userRole); // "admin"
Use const or let to keep the value inside the block.
Comparisons
| Declaration or location | Scope | Can be reassigned? | Notes |
|---|---|---|---|
const value = 1 | Current block, function, or module/global lexical environment | No | The binding cannot be reassigned; object contents may still change. |
let value = 1 | Current block, function, or module/global lexical environment | Yes | Use when the variable must receive a new value. |
var value = 1 | Current function, or global scope if outside a function | Yes | Not block-scoped; avoid in new code. |
| Function parameter | Current function | Yes | Local to each function call. |
| Concept |
|---|
Cheat Sheet
// Global or module-level binding
const appVersion = "1.0";
function example(input) {
// Function scope
let result = input;
if (result > 0) {
// Block scope
const message = "Positive";
return message;
}
return "Not positive";
}
- JavaScript uses lexical scope: where code is written determines what it can access.
- Inner scopes can access outer variables; outer scopes cannot access inner variables.
- Use
constby default. - Use
letwhen reassignment is required. letandconstare block-scoped.varis function-scoped and can escapeifor loop blocks.- Function parameters are local to that function call.
- Avoid mutable globals; pass values as parameters or use module exports when possible.
- In browser classic scripts, top-level
varmay becomewindowproperties. Top-levelletand do not.
FAQ
What is variable scope in JavaScript?
Scope defines where a variable name can be read or changed. It determines which code can access that variable.
Can a function access a global variable in JavaScript?
Yes. A function can access variables from its outer, global scope unless a local variable with the same name shadows it.
Can code outside a function access variables declared inside it?
No. Function-local variables are not directly accessible outside that function. Return a value if outside code needs the result.
Is let function-scoped in JavaScript?
No. let is block-scoped. When declared inside a function but not inside a smaller block, it is available throughout that function.
Is var block-scoped?
No. var is function-scoped. A var declared inside an if block is still available elsewhere in the containing function.
Where are global variables stored in JavaScript?
JavaScript keeps global bindings in its global environment. In browser classic scripts, top-level var commonly also appears on the window global object. Top-level let and const do not become window properties, and ES module declarations are scoped to the module.
Mini Project
Description
Build a small order-summary function that demonstrates function scope, block scope, and safe access to an outer configuration value. This mirrors how applications calculate and format data without exposing temporary implementation details.
Goal
Create a function that returns a readable order summary while keeping calculation variables local.
Requirements
- Declare a
currencyconstant outside the function. - Create a
createOrderSummaryfunction that accepts an item name and price. - Return an error message when the price is not greater than zero.
- Use a block-scoped variable to format a valid price.
- Return a summary string that includes the item name, formatted price, and currency.
Keep learning
Related questions
Abort Ajax Requests with jQuery jqXHR.abort()
Learn how to cancel an in-progress jQuery Ajax request with jqXHR.abort(), handle abort status safely, and avoid stale UI updates.
Access the Correct this Inside a JavaScript Callback
Learn why JavaScript this changes in callbacks and how to preserve an object context using bind, arrow functions, and event handler patterns.
Add Key-Value Pairs to JavaScript Objects
Learn how to add key-value pairs to JavaScript objects with dot and bracket notation, dynamic keys, examples, and common mistakes.