Function Scope
Introduction
Function scope means a variable is visible throughout the function in which it is declared. Before ES6 introduced let and const, JavaScript developers mostly used var, and var is scoped to the nearest function — not to if, for, or other blocks.
This is the reason many older interview snippets feel surprising: a var declared deep inside an if can still be read later in the same function.
Why This Matters
Function scope explains var hoisting, nested functions, and many closure questions. If you cannot trace where a function-local variable exists, you will struggle to explain why a returned inner function can still access it after the outer function finishes.
Theory
A function creates a local environment
Every function call creates a new function environment containing:
- its parameters,
- variables declared with
var, - function declarations,
- and block-scoped declarations inside nested blocks (
let/const) where applicable.
When the function returns, its ordinary local frame is done — unless an inner function closes over variables from it.
var is function-scoped
var belongs to the nearest function, even when written inside a block. The declaration is hoisted to the top of the function and initialised to undefined; the assignment stays where it is.
| Construct | Scope boundary for var | Scope boundary for let/const |
|---|---|---|
| Function body | yes | yes |
if block | no | yes |
for block | no | yes |
Plain {} block | no | yes |
Nested functions
A nested function can read variables from its own scope, its outer function's scope, and then the global scope. The reverse is not true: an outer function cannot read variables declared inside an inner function.
Parameters are local too
Function parameters behave like local bindings. If an inner function uses a parameter, that parameter is part of the outer function's lexical environment and can be captured by a closure.
Visual Diagrams
outer(name) function scope
var greeting
|
+-- inner() function scope
local variables
| not found locally
v
outer scope: name, greeting
| not found
v
global scopeInner functions can see outward; outer functions cannot see inward.
Code Examples
A nested function reads outer function variables
inner can use both greeting and name because it is written inside outer.
`var` ignores block boundaries
The declaration belongs to the whole function, even though it appears inside an if block.
Output Prediction
Predict the output #1
1function test(flag) {2 if (flag) {3 var functionScoped = 'visible';4 let blockScoped = 'hidden';5 }6 7 console.log(functionScoped);8 console.log(typeof blockScoped);9}10 11test(true);Interview Questions
1What does it mean that `var` is function-scoped?
A var declaration is scoped to the nearest enclosing function, not to the nearest block. Its declaration is hoisted and initialised to undefined for the whole function, while the assignment happens at runtime where written. Therefore var declared inside an if or for can still be read elsewhere in the same function.
Follow-ups
- How is this different from `let`?
- What value do you get before the assignment runs?
2Can an inner function access variables from an outer function? Can the outer function access variables from the inner function?
The inner function can access variables from the outer function through lexical scope. The outer function cannot access variables declared inside the inner function because lookup only walks outward, never inward.
Quiz
1. What does `choose(false)` return here? `function choose(flag){ if(flag){ var x = 1; } return x; }`
2. A nested function's identifier lookup can move…
Summary
- Each function call creates a local function scope for parameters, `var`, and function declarations.
- `var` is scoped to the nearest function, not the nearest block.
- Nested functions can read variables from outer functions via the scope chain.
- Function scope is the foundation for closures: an inner function can keep using outer variables later.